blob: 667a8a21d439c617854beca6177be5518b877042 [file] [log] [blame]
Wesley Chenge5eed722014-01-13 14:47:46 +05301/* Copyright (c) 2012-2014, 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
Vijayavardhan Vennapusab77e1432013-10-03 18:17:50 +05301045 if (qdss_enabled) {
1046 dwc->tx_fifo_reduced = true;
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05301047 dwc->tx_fifo_size = mdwc->qdss_tx_fifo_size;
Vijayavardhan Vennapusab77e1432013-10-03 18:17:50 +05301048 } else {
1049 dwc->tx_fifo_reduced = false;
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05301050 dwc->tx_fifo_size = mdwc->tx_fifo_size;
Vijayavardhan Vennapusab77e1432013-10-03 18:17:50 +05301051 }
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05301052}
1053EXPORT_SYMBOL(dwc3_tx_fifo_resize_request);
1054
Manu Gautam6eb13e32013-02-01 15:19:15 +05301055static void dwc3_restart_usb_work(struct work_struct *w)
1056{
1057 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
1058 restart_usb_work);
1059
1060 dev_dbg(mdwc->dev, "%s\n", __func__);
1061
1062 if (atomic_read(&mdwc->in_lpm) || !mdwc->otg_xceiv) {
1063 dev_err(mdwc->dev, "%s failed!!!\n", __func__);
1064 return;
1065 }
1066
1067 if (!mdwc->ext_xceiv.bsv) {
1068 dev_dbg(mdwc->dev, "%s bailing out in disconnect\n", __func__);
1069 return;
1070 }
1071
1072 /* Reset active USB connection */
1073 mdwc->ext_xceiv.bsv = false;
1074 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
1075 /* Make sure disconnect is processed before sending connect */
1076 flush_delayed_work(&mdwc->resume_work);
1077
1078 mdwc->ext_xceiv.bsv = true;
1079 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
1080}
1081
1082/**
1083 * Reset USB peripheral connection
1084 * Inform OTG for Vbus LOW followed by Vbus HIGH notification.
1085 * This performs full hardware reset and re-initialization which
1086 * might be required by some DBM client driver during uninit/cleanup.
1087 */
Jack Pham62c19a42013-07-09 17:55:09 -07001088void msm_dwc3_restart_usb_session(struct usb_gadget *gadget)
Manu Gautam6eb13e32013-02-01 15:19:15 +05301089{
Jack Pham62c19a42013-07-09 17:55:09 -07001090 struct dwc3 *dwc = container_of(gadget, struct dwc3, gadget);
1091 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
1092
1093 if (mdwc)
1094 return;
Manu Gautam6eb13e32013-02-01 15:19:15 +05301095
1096 dev_dbg(mdwc->dev, "%s\n", __func__);
1097 queue_work(system_nrt_wq, &mdwc->restart_usb_work);
Manu Gautam6eb13e32013-02-01 15:19:15 +05301098}
1099EXPORT_SYMBOL(msm_dwc3_restart_usb_session);
1100
Jack Phamfadd6432012-12-07 19:03:41 -08001101/**
1102 * msm_register_usb_ext_notification: register for event notification
1103 * @info: pointer to client usb_ext_notification structure. May be NULL.
1104 *
1105 * @return int - 0 on success, negative on error
1106 */
1107int msm_register_usb_ext_notification(struct usb_ext_notification *info)
1108{
1109 pr_debug("%s usb_ext: %p\n", __func__, info);
1110
1111 if (info) {
1112 if (usb_ext) {
1113 pr_err("%s: already registered\n", __func__);
1114 return -EEXIST;
1115 }
1116
1117 if (!info->notify) {
1118 pr_err("%s: notify is NULL\n", __func__);
1119 return -EINVAL;
1120 }
1121 }
1122
1123 usb_ext = info;
1124 return 0;
1125}
1126EXPORT_SYMBOL(msm_register_usb_ext_notification);
1127
Manu Gautam60e01352012-05-29 09:00:34 +05301128/* HSPHY */
Jack Pham4b00e702013-07-03 17:10:36 -07001129static int dwc3_hsusb_config_vddcx(struct dwc3_msm *dwc, int high)
Manu Gautam60e01352012-05-29 09:00:34 +05301130{
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301131 int min_vol, max_vol, ret;
Manu Gautam60e01352012-05-29 09:00:34 +05301132
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301133 max_vol = dwc->vdd_high_vol_level;
1134 min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
Manu Gautam60e01352012-05-29 09:00:34 +05301135 ret = regulator_set_voltage(dwc->hsusb_vddcx, min_vol, max_vol);
1136 if (ret) {
1137 dev_err(dwc->dev, "unable to set voltage for HSUSB_VDDCX\n");
1138 return ret;
1139 }
1140
1141 dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
1142 min_vol, max_vol);
1143
1144 return ret;
1145}
1146
Jack Pham4b00e702013-07-03 17:10:36 -07001147static int dwc3_hsusb_ldo_init(struct dwc3_msm *dwc, int init)
Manu Gautam60e01352012-05-29 09:00:34 +05301148{
1149 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301150
1151 if (!init) {
1152 regulator_set_voltage(dwc->hsusb_1p8, 0, USB_HSPHY_1P8_VOL_MAX);
1153 regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
1154 return 0;
1155 }
1156
1157 dwc->hsusb_3p3 = devm_regulator_get(dwc->dev, "HSUSB_3p3");
1158 if (IS_ERR(dwc->hsusb_3p3)) {
1159 dev_err(dwc->dev, "unable to get hsusb 3p3\n");
1160 return PTR_ERR(dwc->hsusb_3p3);
1161 }
1162
1163 rc = regulator_set_voltage(dwc->hsusb_3p3,
1164 USB_HSPHY_3P3_VOL_MIN, USB_HSPHY_3P3_VOL_MAX);
1165 if (rc) {
1166 dev_err(dwc->dev, "unable to set voltage for hsusb 3p3\n");
1167 return rc;
1168 }
1169 dwc->hsusb_1p8 = devm_regulator_get(dwc->dev, "HSUSB_1p8");
1170 if (IS_ERR(dwc->hsusb_1p8)) {
1171 dev_err(dwc->dev, "unable to get hsusb 1p8\n");
1172 rc = PTR_ERR(dwc->hsusb_1p8);
1173 goto devote_3p3;
1174 }
1175 rc = regulator_set_voltage(dwc->hsusb_1p8,
1176 USB_HSPHY_1P8_VOL_MIN, USB_HSPHY_1P8_VOL_MAX);
1177 if (rc) {
1178 dev_err(dwc->dev, "unable to set voltage for hsusb 1p8\n");
1179 goto devote_3p3;
1180 }
1181
1182 return 0;
1183
1184devote_3p3:
1185 regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
1186
1187 return rc;
1188}
1189
Jack Pham4b00e702013-07-03 17:10:36 -07001190static int dwc3_hsusb_ldo_enable(struct dwc3_msm *dwc, int on)
Manu Gautam60e01352012-05-29 09:00:34 +05301191{
1192 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301193
1194 dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
1195
1196 if (!on)
1197 goto disable_regulators;
1198
1199
1200 rc = regulator_set_optimum_mode(dwc->hsusb_1p8, USB_HSPHY_1P8_HPM_LOAD);
1201 if (rc < 0) {
1202 dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_1p8\n");
1203 return rc;
1204 }
1205
1206 rc = regulator_enable(dwc->hsusb_1p8);
1207 if (rc) {
1208 dev_err(dwc->dev, "Unable to enable HSUSB_1p8\n");
1209 goto put_1p8_lpm;
1210 }
1211
1212 rc = regulator_set_optimum_mode(dwc->hsusb_3p3, USB_HSPHY_3P3_HPM_LOAD);
1213 if (rc < 0) {
1214 dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_3p3\n");
1215 goto disable_1p8;
1216 }
1217
1218 rc = regulator_enable(dwc->hsusb_3p3);
1219 if (rc) {
1220 dev_err(dwc->dev, "Unable to enable HSUSB_3p3\n");
1221 goto put_3p3_lpm;
1222 }
1223
1224 return 0;
1225
1226disable_regulators:
1227 rc = regulator_disable(dwc->hsusb_3p3);
1228 if (rc)
1229 dev_err(dwc->dev, "Unable to disable HSUSB_3p3\n");
1230
1231put_3p3_lpm:
1232 rc = regulator_set_optimum_mode(dwc->hsusb_3p3, 0);
1233 if (rc < 0)
1234 dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_3p3\n");
1235
1236disable_1p8:
1237 rc = regulator_disable(dwc->hsusb_1p8);
1238 if (rc)
1239 dev_err(dwc->dev, "Unable to disable HSUSB_1p8\n");
1240
1241put_1p8_lpm:
1242 rc = regulator_set_optimum_mode(dwc->hsusb_1p8, 0);
1243 if (rc < 0)
1244 dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_1p8\n");
1245
1246 return rc < 0 ? rc : 0;
1247}
1248
1249/* SSPHY */
Jack Pham4b00e702013-07-03 17:10:36 -07001250static int dwc3_ssusb_config_vddcx(struct dwc3_msm *dwc, int high)
Manu Gautam60e01352012-05-29 09:00:34 +05301251{
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301252 int min_vol, max_vol, ret;
Manu Gautam60e01352012-05-29 09:00:34 +05301253
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05301254 max_vol = dwc->vdd_high_vol_level;
1255 min_vol = high ? dwc->vdd_low_vol_level : dwc->vdd_no_vol_level;
Manu Gautam60e01352012-05-29 09:00:34 +05301256 ret = regulator_set_voltage(dwc->ssusb_vddcx, min_vol, max_vol);
1257 if (ret) {
1258 dev_err(dwc->dev, "unable to set voltage for SSUSB_VDDCX\n");
1259 return ret;
1260 }
1261
1262 dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
1263 min_vol, max_vol);
1264 return ret;
1265}
1266
1267/* 3.3v supply not needed for SS PHY */
Jack Pham4b00e702013-07-03 17:10:36 -07001268static int dwc3_ssusb_ldo_init(struct dwc3_msm *dwc, int init)
Manu Gautam60e01352012-05-29 09:00:34 +05301269{
1270 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301271
1272 if (!init) {
1273 regulator_set_voltage(dwc->ssusb_1p8, 0, USB_SSPHY_1P8_VOL_MAX);
1274 return 0;
1275 }
1276
1277 dwc->ssusb_1p8 = devm_regulator_get(dwc->dev, "SSUSB_1p8");
1278 if (IS_ERR(dwc->ssusb_1p8)) {
1279 dev_err(dwc->dev, "unable to get ssusb 1p8\n");
1280 return PTR_ERR(dwc->ssusb_1p8);
1281 }
1282 rc = regulator_set_voltage(dwc->ssusb_1p8,
1283 USB_SSPHY_1P8_VOL_MIN, USB_SSPHY_1P8_VOL_MAX);
1284 if (rc)
1285 dev_err(dwc->dev, "unable to set voltage for ssusb 1p8\n");
1286
1287 return rc;
1288}
1289
Jack Pham4b00e702013-07-03 17:10:36 -07001290static int dwc3_ssusb_ldo_enable(struct dwc3_msm *dwc, int on)
Manu Gautam60e01352012-05-29 09:00:34 +05301291{
1292 int rc = 0;
Manu Gautam60e01352012-05-29 09:00:34 +05301293
Jack Pham4b00e702013-07-03 17:10:36 -07001294 dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
Manu Gautam60e01352012-05-29 09:00:34 +05301295
1296 if (!on)
1297 goto disable_regulators;
1298
1299
1300 rc = regulator_set_optimum_mode(dwc->ssusb_1p8, USB_SSPHY_1P8_HPM_LOAD);
1301 if (rc < 0) {
1302 dev_err(dwc->dev, "Unable to set HPM of SSUSB_1p8\n");
1303 return rc;
1304 }
1305
1306 rc = regulator_enable(dwc->ssusb_1p8);
1307 if (rc) {
1308 dev_err(dwc->dev, "Unable to enable SSUSB_1p8\n");
1309 goto put_1p8_lpm;
1310 }
1311
1312 return 0;
1313
1314disable_regulators:
1315 rc = regulator_disable(dwc->ssusb_1p8);
1316 if (rc)
1317 dev_err(dwc->dev, "Unable to disable SSUSB_1p8\n");
1318
1319put_1p8_lpm:
1320 rc = regulator_set_optimum_mode(dwc->ssusb_1p8, 0);
1321 if (rc < 0)
1322 dev_err(dwc->dev, "Unable to set LPM of SSUSB_1p8\n");
1323
1324 return rc < 0 ? rc : 0;
1325}
1326
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001327/*
1328 * Config Global Distributed Switch Controller (GDSC)
1329 * to support controller power collapse
1330 */
Jack Pham80162462013-07-10 11:59:01 -07001331static int dwc3_msm_config_gdsc(struct dwc3_msm *mdwc, int on)
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001332{
1333 int ret = 0;
1334
Jack Pham80162462013-07-10 11:59:01 -07001335 if (IS_ERR(mdwc->dwc3_gdsc))
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001336 return 0;
1337
Jack Pham80162462013-07-10 11:59:01 -07001338 if (!mdwc->dwc3_gdsc) {
1339 mdwc->dwc3_gdsc = devm_regulator_get(mdwc->dev,
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001340 "USB3_GDSC");
Jack Pham80162462013-07-10 11:59:01 -07001341 if (IS_ERR(mdwc->dwc3_gdsc))
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001342 return 0;
1343 }
1344
1345 if (on) {
Jack Pham80162462013-07-10 11:59:01 -07001346 ret = regulator_enable(mdwc->dwc3_gdsc);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001347 if (ret) {
Jack Pham80162462013-07-10 11:59:01 -07001348 dev_err(mdwc->dev, "unable to enable usb3 gdsc\n");
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001349 return ret;
1350 }
1351 } else {
Jack Pham80162462013-07-10 11:59:01 -07001352 regulator_disable(mdwc->dwc3_gdsc);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001353 }
1354
1355 return 0;
1356}
1357
Jack Pham4b00e702013-07-03 17:10:36 -07001358static int dwc3_msm_link_clk_reset(struct dwc3_msm *mdwc, bool assert)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301359{
1360 int ret = 0;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301361
1362 if (assert) {
1363 /* Using asynchronous block reset to the hardware */
1364 dev_dbg(mdwc->dev, "block_reset ASSERT\n");
1365 clk_disable_unprepare(mdwc->ref_clk);
1366 clk_disable_unprepare(mdwc->iface_clk);
1367 clk_disable_unprepare(mdwc->core_clk);
1368 ret = clk_reset(mdwc->core_clk, CLK_RESET_ASSERT);
1369 if (ret)
1370 dev_err(mdwc->dev, "dwc3 core_clk assert failed\n");
1371 } else {
1372 dev_dbg(mdwc->dev, "block_reset DEASSERT\n");
1373 ret = clk_reset(mdwc->core_clk, CLK_RESET_DEASSERT);
1374 ndelay(200);
1375 clk_prepare_enable(mdwc->core_clk);
1376 clk_prepare_enable(mdwc->ref_clk);
1377 clk_prepare_enable(mdwc->iface_clk);
1378 if (ret)
1379 dev_err(mdwc->dev, "dwc3 core_clk deassert failed\n");
1380 }
1381
1382 return ret;
1383}
1384
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301385/* Reinitialize SSPHY parameters by overriding using QSCRATCH CR interface */
Jack Pham80162462013-07-10 11:59:01 -07001386static void dwc3_msm_ss_phy_reg_init(struct dwc3_msm *mdwc)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301387{
1388 u32 data = 0;
1389
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301390 /*
1391 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
1392 * in HS mode instead of SS mode. Workaround it by asserting
1393 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
1394 */
Jack Pham80162462013-07-10 11:59:01 -07001395 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x102D);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301396 data |= (1 << 7);
Jack Pham80162462013-07-10 11:59:01 -07001397 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x102D, data);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301398
Jack Pham80162462013-07-10 11:59:01 -07001399 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1010);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301400 data &= ~0xFF0;
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301401 data |= 0x20;
Jack Pham80162462013-07-10 11:59:01 -07001402 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1010, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301403
1404 /*
1405 * Fix RX Equalization setting as follows
1406 * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
1407 * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
1408 * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
1409 * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
1410 */
Jack Pham80162462013-07-10 11:59:01 -07001411 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1006);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301412 data &= ~(1 << 6);
1413 data |= (1 << 7);
1414 data &= ~(0x7 << 8);
1415 data |= (0x3 << 8);
1416 data |= (0x1 << 11);
Jack Pham80162462013-07-10 11:59:01 -07001417 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1006, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301418
1419 /*
1420 * Set EQ and TX launch amplitudes as follows
1421 * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
1422 * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
1423 * LANE0.TX_OVRD_DRV_LO.EN set to 1.
1424 */
Jack Pham80162462013-07-10 11:59:01 -07001425 data = dwc3_msm_ssusb_read_phycreg(mdwc->base, 0x1002);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301426 data &= ~0x3F80;
Vijayavardhan Vennapusa9f74b1b2013-09-23 19:22:17 +05301427 if (ss_phy_override_deemphasis)
1428 mdwc->deemphasis_val = ss_phy_override_deemphasis;
1429 if (mdwc->deemphasis_val)
1430 data |= (mdwc->deemphasis_val << 7);
1431 else
1432 data |= (0x16 << 7);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301433 data &= ~0x7F;
1434 data |= (0x7F | (1 << 14));
Jack Pham80162462013-07-10 11:59:01 -07001435 dwc3_msm_ssusb_write_phycreg(mdwc->base, 0x1002, data);
Vijayavardhan Vennapusa164b0f42013-01-17 19:33:53 +05301436
Jack Pham63c8c702013-04-24 19:21:33 -07001437 /*
1438 * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
1439 * TX_FULL_SWING [26:20] amplitude to 127
1440 * TX_DEEMPH_3_5DB [13:8] to 22
1441 * LOS_BIAS [2:0] to 0x5
1442 */
Jack Pham80162462013-07-10 11:59:01 -07001443 dwc3_msm_write_readback(mdwc->base, SS_PHY_PARAM_CTRL_1,
Jack Pham63c8c702013-04-24 19:21:33 -07001444 0x07f03f07, 0x07f01605);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301445}
1446
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301447/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301448static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
1449 unsigned event_status)
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301450{
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301451 if (event_status == DWC3_CONTROLLER_POST_RESET_EVENT) {
1452 dwc3_msm_ss_phy_reg_init(mdwc);
1453 return;
1454 }
1455
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301456 /* SSPHY Initialization: Use ref_clk from pads and set its parameters */
Jack Pham80162462013-07-10 11:59:01 -07001457 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301458 msleep(30);
1459 /* Assert SSPHY reset */
Jack Pham80162462013-07-10 11:59:01 -07001460 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210082);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301461 usleep_range(2000, 2200);
1462 /* De-assert SSPHY reset - power and ref_clock must be ON */
Jack Pham80162462013-07-10 11:59:01 -07001463 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301464 usleep_range(2000, 2200);
1465 /* Ref clock must be stable now, enable ref clock for HS mode */
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301466 dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x11210102);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301467 usleep_range(2000, 2200);
1468 /*
1469 * HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
1470 * and disable RETENTION (power-on default is ENABLED)
1471 */
Jack Pham80162462013-07-10 11:59:01 -07001472 dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301473 usleep_range(2000, 2200);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301474 /* Set XHCI_REV bit (2) to 1 - XHCI version 1.0 */
1475 dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x4);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301476 /*
1477 * write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
1478 * VBUS valid threshold, disconnect valid threshold, DC voltage level,
1479 * preempasis and rise/fall time.
1480 */
1481 if (override_phy_init)
Jack Pham80162462013-07-10 11:59:01 -07001482 mdwc->hsphy_init_seq = override_phy_init;
1483 if (mdwc->hsphy_init_seq)
1484 dwc3_msm_write_readback(mdwc->base,
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301485 PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
Jack Pham80162462013-07-10 11:59:01 -07001486 mdwc->hsphy_init_seq & 0x03FFFFFF);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301487
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301488 /*
1489 * Enable master clock for RAMs to allow BAM to access RAMs when
1490 * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301491 * are seen where RAM clocks get turned OFF in SS mode
1492 */
Jack Pham80162462013-07-10 11:59:01 -07001493 dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
1494 dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301495
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301496 /*
1497 * This is required to restore the POR value after userspace
1498 * is done with charger detection.
1499 */
Jack Pham80162462013-07-10 11:59:01 -07001500 mdwc->qscratch_ctl_val =
1501 dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
Vijayavardhan Vennapusa5b286322013-04-12 12:15:00 +05301502}
1503
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301504static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
1505{
1506 struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
1507
Vijayavardhan Vennapusada8d06c2013-10-22 19:19:57 +05301508 if (dwc->revision < DWC3_REVISION_230A)
1509 return;
1510
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301511 switch (event) {
1512 case DWC3_CONTROLLER_ERROR_EVENT:
1513 dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
1514 dwc3_msm_dump_phy_info(mdwc);
Wesley Chenge5eed722014-01-13 14:47:46 +05301515 dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, 0);
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05301516 /*
1517 * schedule work for doing block reset for recovery from erratic
1518 * error event.
1519 */
1520 queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301521 break;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301522 case DWC3_CONTROLLER_RESET_EVENT:
1523 dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
1524 dwc3_msm_qscratch_reg_init(mdwc, DWC3_CONTROLLER_RESET_EVENT);
1525 break;
1526 case DWC3_CONTROLLER_POST_RESET_EVENT:
1527 dev_dbg(mdwc->dev,
1528 "DWC3_CONTROLLER_POST_RESET_EVENT received\n");
1529 dwc3_msm_qscratch_reg_init(mdwc,
1530 DWC3_CONTROLLER_POST_RESET_EVENT);
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05301531 dwc->tx_fifo_size = mdwc->tx_fifo_size;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301532 break;
Vijayavardhan Vennapusada8d06c2013-10-22 19:19:57 +05301533 case DWC3_CONTROLLER_POST_INITIALIZATION_EVENT:
1534 /* clear LANE0_PWR_PRESENT bit after initialization is done */
1535 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 24),
1536 0x0);
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05301537 default:
1538 dev_dbg(mdwc->dev, "unknown dwc3 event\n");
1539 break;
1540 }
1541}
1542
Jack Pham4b00e702013-07-03 17:10:36 -07001543static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301544{
Jack Pham4b00e702013-07-03 17:10:36 -07001545 struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301546 int ret = 0;
1547
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301548 if (core_reset) {
Jack Pham4b00e702013-07-03 17:10:36 -07001549 ret = dwc3_msm_link_clk_reset(mdwc, 1);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301550 if (ret)
1551 return;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301552
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301553 usleep_range(1000, 1200);
Jack Pham4b00e702013-07-03 17:10:36 -07001554 ret = dwc3_msm_link_clk_reset(mdwc, 0);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301555 if (ret)
1556 return;
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301557
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301558 usleep_range(10000, 12000);
Vijayavardhan Vennapusaf7c01a42013-03-15 15:29:11 +05301559 }
Manu Gautama302f612012-12-18 17:33:06 +05301560
1561 /* Reset the DBM */
Jack Pham62c19a42013-07-09 17:55:09 -07001562 dwc3_msm_dbm_soft_reset(mdwc, 1);
Manu Gautama302f612012-12-18 17:33:06 +05301563 usleep_range(1000, 1200);
Jack Pham62c19a42013-07-09 17:55:09 -07001564 dwc3_msm_dbm_soft_reset(mdwc, 0);
Vijayavardhan Vennapusab7434562012-12-12 16:48:49 +05301565}
1566
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05301567static void dwc3_block_reset_usb_work(struct work_struct *w)
1568{
1569 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
1570 usb_block_reset_work);
Wesley Chenge5eed722014-01-13 14:47:46 +05301571 u32 reg;
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05301572
1573 dev_dbg(mdwc->dev, "%s\n", __func__);
1574
1575 dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
Wesley Chenge5eed722014-01-13 14:47:46 +05301576
1577 reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
1578 DWC3_DEVTEN_CMDCMPLTEN |
1579 DWC3_DEVTEN_ERRTICERREN |
1580 DWC3_DEVTEN_WKUPEVTEN |
1581 DWC3_DEVTEN_ULSTCNGEN |
1582 DWC3_DEVTEN_CONNECTDONEEN |
1583 DWC3_DEVTEN_USBRSTEN |
1584 DWC3_DEVTEN_DISCONNEVTEN);
1585 dwc3_msm_write_reg(mdwc->base, DWC3_DEVTEN, reg);
1586
1587
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05301588}
1589
Manu Gautam8c642812012-06-07 10:35:10 +05301590static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
1591{
1592 u32 chg_ctrl;
1593
1594 /* Turn off VDP_SRC */
1595 dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
1596 msleep(20);
1597
1598 /* Before proceeding make sure VDP_SRC is OFF */
1599 chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
1600 if (chg_ctrl & 0x3F)
1601 dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
1602 __func__, chg_ctrl);
1603 /*
1604 * Configure DM as current source, DP as current sink
1605 * and enable battery charging comparators.
1606 */
1607 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34);
1608}
1609
Manu Gautama1e331d2013-02-07 14:55:05 +05301610static bool dwc3_chg_det_check_linestate(struct dwc3_msm *mdwc)
1611{
1612 u32 chg_det;
Jack Pham9b4606b2013-04-02 17:32:25 -07001613
1614 if (!prop_chg_detect)
1615 return false;
Manu Gautama1e331d2013-02-07 14:55:05 +05301616
1617 chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
Jack Pham9b4606b2013-04-02 17:32:25 -07001618 return chg_det & (3 << 8);
Manu Gautama1e331d2013-02-07 14:55:05 +05301619}
1620
Manu Gautam8c642812012-06-07 10:35:10 +05301621static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc)
1622{
1623 u32 chg_det;
1624 bool ret = false;
1625
1626 chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
1627 ret = chg_det & 1;
1628
1629 return ret;
1630}
1631
1632static void dwc3_chg_enable_primary_det(struct dwc3_msm *mdwc)
1633{
1634 /*
1635 * Configure DP as current source, DM as current sink
1636 * and enable battery charging comparators.
1637 */
1638 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x30);
1639}
1640
1641static inline bool dwc3_chg_check_dcd(struct dwc3_msm *mdwc)
1642{
1643 u32 chg_state;
1644 bool ret = false;
1645
1646 chg_state = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
1647 ret = chg_state & 2;
1648
1649 return ret;
1650}
1651
1652static inline void dwc3_chg_disable_dcd(struct dwc3_msm *mdwc)
1653{
1654 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x0);
1655}
1656
1657static inline void dwc3_chg_enable_dcd(struct dwc3_msm *mdwc)
1658{
1659 /* Data contact detection enable, DCDENB */
1660 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x2);
1661}
1662
1663static void dwc3_chg_block_reset(struct dwc3_msm *mdwc)
1664{
1665 u32 chg_ctrl;
1666
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301667 dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
1668 mdwc->qscratch_ctl_val);
Manu Gautam8c642812012-06-07 10:35:10 +05301669 /* Clear charger detecting control bits */
1670 dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
1671
1672 /* Clear alt interrupt latch and enable bits */
1673 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1674 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x0);
1675
1676 udelay(100);
1677
1678 /* Before proceeding make sure charger block is RESET */
1679 chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
1680 if (chg_ctrl & 0x3F)
1681 dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
1682 __func__, chg_ctrl);
1683}
1684
1685static const char *chg_to_string(enum dwc3_chg_type chg_type)
1686{
1687 switch (chg_type) {
Manu Gautama1e331d2013-02-07 14:55:05 +05301688 case DWC3_SDP_CHARGER: return "USB_SDP_CHARGER";
1689 case DWC3_DCP_CHARGER: return "USB_DCP_CHARGER";
1690 case DWC3_CDP_CHARGER: return "USB_CDP_CHARGER";
1691 case DWC3_PROPRIETARY_CHARGER: return "USB_PROPRIETARY_CHARGER";
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301692 case DWC3_FLOATED_CHARGER: return "USB_FLOATED_CHARGER";
Vijayavardhan Vennapusaa04e0c92013-06-04 12:37:10 +05301693 default: return "UNKNOWN_CHARGER";
Manu Gautam8c642812012-06-07 10:35:10 +05301694 }
1695}
1696
1697#define DWC3_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
1698#define DWC3_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
1699#define DWC3_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
1700#define DWC3_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
1701
1702static void dwc3_chg_detect_work(struct work_struct *w)
1703{
1704 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
1705 bool is_dcd = false, tmout, vout;
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301706 static bool dcd;
Manu Gautam8c642812012-06-07 10:35:10 +05301707 unsigned long delay;
1708
1709 dev_dbg(mdwc->dev, "chg detection work\n");
1710 switch (mdwc->chg_state) {
1711 case USB_CHG_STATE_UNDEFINED:
1712 dwc3_chg_block_reset(mdwc);
1713 dwc3_chg_enable_dcd(mdwc);
1714 mdwc->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
1715 mdwc->dcd_retries = 0;
1716 delay = DWC3_CHG_DCD_POLL_TIME;
1717 break;
1718 case USB_CHG_STATE_WAIT_FOR_DCD:
1719 is_dcd = dwc3_chg_check_dcd(mdwc);
1720 tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
1721 if (is_dcd || tmout) {
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301722 if (is_dcd)
1723 dcd = true;
1724 else
1725 dcd = false;
Manu Gautam8c642812012-06-07 10:35:10 +05301726 dwc3_chg_disable_dcd(mdwc);
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301727 usleep_range(1000, 1200);
Manu Gautama1e331d2013-02-07 14:55:05 +05301728 if (dwc3_chg_det_check_linestate(mdwc)) {
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301729 mdwc->charger.chg_type =
Manu Gautama1e331d2013-02-07 14:55:05 +05301730 DWC3_PROPRIETARY_CHARGER;
1731 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1732 delay = 0;
1733 break;
1734 }
Manu Gautam8c642812012-06-07 10:35:10 +05301735 dwc3_chg_enable_primary_det(mdwc);
1736 delay = DWC3_CHG_PRIMARY_DET_TIME;
1737 mdwc->chg_state = USB_CHG_STATE_DCD_DONE;
1738 } else {
1739 delay = DWC3_CHG_DCD_POLL_TIME;
1740 }
1741 break;
1742 case USB_CHG_STATE_DCD_DONE:
1743 vout = dwc3_chg_det_check_output(mdwc);
1744 if (vout) {
1745 dwc3_chg_enable_secondary_det(mdwc);
1746 delay = DWC3_CHG_SECONDARY_DET_TIME;
1747 mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
1748 } else {
Vijayavardhan Vennapusab11d7fd2013-07-01 16:40:57 +05301749 /*
1750 * Detect floating charger only if propreitary
1751 * charger detection is enabled.
1752 */
1753 if (!dcd && prop_chg_detect)
1754 mdwc->charger.chg_type =
1755 DWC3_FLOATED_CHARGER;
1756 else
1757 mdwc->charger.chg_type = DWC3_SDP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301758 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1759 delay = 0;
1760 }
1761 break;
1762 case USB_CHG_STATE_PRIMARY_DONE:
1763 vout = dwc3_chg_det_check_output(mdwc);
1764 if (vout)
Manu Gautama1e331d2013-02-07 14:55:05 +05301765 mdwc->charger.chg_type = DWC3_DCP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301766 else
Manu Gautama1e331d2013-02-07 14:55:05 +05301767 mdwc->charger.chg_type = DWC3_CDP_CHARGER;
Manu Gautam8c642812012-06-07 10:35:10 +05301768 mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE;
1769 /* fall through */
1770 case USB_CHG_STATE_SECONDARY_DONE:
1771 mdwc->chg_state = USB_CHG_STATE_DETECTED;
1772 /* fall through */
1773 case USB_CHG_STATE_DETECTED:
1774 dwc3_chg_block_reset(mdwc);
Manu Gautama48296e2012-12-05 17:37:56 +05301775 /* Enable VDP_SRC */
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301776 if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
Manu Gautama48296e2012-12-05 17:37:56 +05301777 dwc3_msm_write_readback(mdwc->base,
1778 CHARGING_DET_CTRL_REG, 0x1F, 0x10);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301779 if (mdwc->ext_chg_opened) {
1780 init_completion(&mdwc->ext_chg_wait);
1781 mdwc->ext_chg_active = true;
1782 }
1783 }
Manu Gautam8c642812012-06-07 10:35:10 +05301784 dev_dbg(mdwc->dev, "chg_type = %s\n",
1785 chg_to_string(mdwc->charger.chg_type));
1786 mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
1787 &mdwc->charger);
1788 return;
1789 default:
1790 return;
1791 }
1792
1793 queue_delayed_work(system_nrt_wq, &mdwc->chg_work, delay);
1794}
1795
1796static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
1797{
Jack Phamea382b72013-07-09 17:50:20 -07001798 struct dwc3_msm *mdwc = container_of(charger, struct dwc3_msm, charger);
Manu Gautam8c642812012-06-07 10:35:10 +05301799
1800 if (start == false) {
Jack Pham9354c6a2012-12-20 19:19:32 -08001801 dev_dbg(mdwc->dev, "canceling charging detection work\n");
Manu Gautam8c642812012-06-07 10:35:10 +05301802 cancel_delayed_work_sync(&mdwc->chg_work);
1803 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1804 charger->chg_type = DWC3_INVALID_CHARGER;
1805 return;
1806 }
1807
Vijayavardhan Vennapusa01dd0b62014-01-16 17:40:47 +05301808 /* Skip if charger type was already detected externally */
1809 if (mdwc->chg_state == USB_CHG_STATE_DETECTED &&
1810 charger->chg_type != DWC3_INVALID_CHARGER)
1811 return;
1812
Manu Gautam8c642812012-06-07 10:35:10 +05301813 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1814 charger->chg_type = DWC3_INVALID_CHARGER;
1815 queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
1816}
1817
Manu Gautamb5067272012-07-02 09:53:41 +05301818static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
1819{
Manu Gautam2617deb2012-08-31 17:50:06 -07001820 int ret;
Manu Gautama48296e2012-12-05 17:37:56 +05301821 bool dcp;
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301822 bool host_bus_suspend;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301823 bool host_ss_active;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301824 bool host_ss_suspend;
Manu Gautam2617deb2012-08-31 17:50:06 -07001825
Manu Gautamb5067272012-07-02 09:53:41 +05301826 dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
1827
1828 if (atomic_read(&mdwc->in_lpm)) {
1829 dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
1830 return 0;
1831 }
1832
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301833 host_ss_active = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC) & PORT_PE;
Manu Gautama48296e2012-12-05 17:37:56 +05301834 if (mdwc->hs_phy_irq)
1835 disable_irq(mdwc->hs_phy_irq);
1836
Manu Gautam98013c22012-11-20 17:42:42 +05301837 if (cancel_delayed_work_sync(&mdwc->chg_work))
1838 dev_dbg(mdwc->dev, "%s: chg_work was pending\n", __func__);
1839 if (mdwc->chg_state != USB_CHG_STATE_DETECTED) {
1840 /* charger detection wasn't complete; re-init flags */
1841 mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
1842 mdwc->charger.chg_type = DWC3_INVALID_CHARGER;
Manu Gautama48296e2012-12-05 17:37:56 +05301843 dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG,
1844 0x37, 0x0);
Manu Gautam98013c22012-11-20 17:42:42 +05301845 }
1846
Manu Gautam840f4fe2013-04-16 16:50:30 +05301847 dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
Vijayavardhan Vennapusac4974862013-07-23 17:36:37 +05301848 (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
1849 (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301850 host_bus_suspend = mdwc->host_mode == 1;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301851 host_ss_suspend = host_bus_suspend && host_ss_active;
Manu Gautam377821c2012-09-28 16:53:24 +05301852
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05301853 if (!dcp && !host_bus_suspend)
1854 dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
1855 mdwc->qscratch_ctl_val);
1856
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05301857 /* Sequence to put SSPHY in low power state:
1858 * 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
1859 * 2. Clear REF_USE_PAD in SS_PHY_CTRL_REG
1860 * 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
1861 * 4. Disable SSPHY ref clk
1862 */
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301863 if (!host_ss_suspend) {
1864 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
1865 0x0);
1866 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
1867 0x0);
1868 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05301869 (1 << 26));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301870 }
Manu Gautam377821c2012-09-28 16:53:24 +05301871 usleep_range(1000, 1200);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301872 if (!host_ss_suspend)
1873 clk_disable_unprepare(mdwc->ref_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05301874
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301875 if (host_bus_suspend) {
1876 /* Sequence for host bus suspend case:
1877 * 1. Set suspend and sleep bits in GUSB2PHYCONFIG reg
1878 * 2. Clear interrupt latch register and enable BSV, ID HV intr
1879 * 3. Enable DP and DM HV interrupts in ALT_INTERRUPT_EN_REG
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301880 */
1881 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
1882 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
1883 0x00000140);
1884 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1885 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1886 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1887 0x18000, 0x18000);
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301888 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0xFC0);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301889 udelay(5);
1890 } else {
1891 /* Sequence to put hardware in low power state:
1892 * 1. Set OTGDISABLE to disable OTG block in HSPHY (saves power)
1893 * 2. Clear charger detection control fields (performed above)
1894 * 3. SUSPEND PHY and turn OFF core clock after some delay
1895 * 4. Clear interrupt latch register and enable BSV, ID HV intr
1896 * 5. Enable PHY retention
1897 */
1898 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x1000,
1899 0x1000);
1900 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1901 0xC00000, 0x800000);
1902 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
1903 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
1904 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1905 0x18000, 0x18000);
1906 if (!dcp)
1907 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
1908 0x2, 0x0);
1909 }
Manu Gautam377821c2012-09-28 16:53:24 +05301910
1911 /* make sure above writes are completed before turning off clocks */
1912 wmb();
Hemant Kumar086bf6b2013-06-10 19:29:27 -07001913
1914 /* remove vote for controller power collapse */
1915 if (!host_bus_suspend)
1916 dwc3_msm_config_gdsc(mdwc, 0);
1917
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301918 if (!host_ss_suspend) {
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301919 clk_disable_unprepare(mdwc->core_clk);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301920 mdwc->lpm_flags |= MDWC3_PHY_REF_AND_CORECLK_OFF;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301921 }
Manu Gautam377821c2012-09-28 16:53:24 +05301922 clk_disable_unprepare(mdwc->iface_clk);
1923
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301924 if (!host_bus_suspend)
Jack Pham22698b82013-02-13 17:45:06 -08001925 clk_disable_unprepare(mdwc->utmi_clk);
1926
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301927 if (!host_bus_suspend) {
Jack Pham22698b82013-02-13 17:45:06 -08001928 /* USB PHY no more requires TCXO */
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05301929 clk_disable_unprepare(mdwc->xo_clk);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301930 mdwc->lpm_flags |= MDWC3_TCXO_SHUTDOWN;
Jack Pham22698b82013-02-13 17:45:06 -08001931 }
Manu Gautamb5067272012-07-02 09:53:41 +05301932
Manu Gautam2617deb2012-08-31 17:50:06 -07001933 if (mdwc->bus_perf_client) {
1934 ret = msm_bus_scale_client_update_request(
1935 mdwc->bus_perf_client, 0);
1936 if (ret)
1937 dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
1938 }
1939
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301940 if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
1941 !host_bus_suspend)
Jack Pham4b00e702013-07-03 17:10:36 -07001942 dwc3_hsusb_ldo_enable(mdwc, 0);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05301943
Jack Pham4b00e702013-07-03 17:10:36 -07001944 dwc3_ssusb_ldo_enable(mdwc, 0);
1945 dwc3_ssusb_config_vddcx(mdwc, 0);
Manu Gautam840f4fe2013-04-16 16:50:30 +05301946 if (!host_bus_suspend && !dcp)
Jack Pham4b00e702013-07-03 17:10:36 -07001947 dwc3_hsusb_config_vddcx(mdwc, 0);
Jack Pham924cbe872013-07-10 16:40:55 -07001948 pm_relax(mdwc->dev);
Manu Gautamb5067272012-07-02 09:53:41 +05301949 atomic_set(&mdwc->in_lpm, 1);
Manu Gautam377821c2012-09-28 16:53:24 +05301950
Manu Gautamb5067272012-07-02 09:53:41 +05301951 dev_info(mdwc->dev, "DWC3 in low power mode\n");
1952
Manu Gautam840f4fe2013-04-16 16:50:30 +05301953 if (mdwc->hs_phy_irq) {
Manu Gautama48296e2012-12-05 17:37:56 +05301954 enable_irq(mdwc->hs_phy_irq);
Manu Gautam840f4fe2013-04-16 16:50:30 +05301955 /* with DCP we dont require wakeup using HS_PHY_IRQ */
1956 if (dcp)
1957 disable_irq_wake(mdwc->hs_phy_irq);
1958 }
Manu Gautama48296e2012-12-05 17:37:56 +05301959
Manu Gautamb5067272012-07-02 09:53:41 +05301960 return 0;
1961}
1962
1963static int dwc3_msm_resume(struct dwc3_msm *mdwc)
1964{
Manu Gautam2617deb2012-08-31 17:50:06 -07001965 int ret;
Manu Gautama48296e2012-12-05 17:37:56 +05301966 bool dcp;
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301967 bool host_bus_suspend;
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301968 bool resume_from_core_clk_off = false;
Manu Gautam2617deb2012-08-31 17:50:06 -07001969
Manu Gautamb5067272012-07-02 09:53:41 +05301970 dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
1971
1972 if (!atomic_read(&mdwc->in_lpm)) {
1973 dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__);
1974 return 0;
1975 }
1976
Jack Pham924cbe872013-07-10 16:40:55 -07001977 pm_stay_awake(mdwc->dev);
Manu Gautam377821c2012-09-28 16:53:24 +05301978
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05301979 if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
1980 resume_from_core_clk_off = true;
1981
Manu Gautam2617deb2012-08-31 17:50:06 -07001982 if (mdwc->bus_perf_client) {
1983 ret = msm_bus_scale_client_update_request(
1984 mdwc->bus_perf_client, 1);
1985 if (ret)
1986 dev_err(mdwc->dev, "Failed to vote for bus scaling\n");
1987 }
1988
Manu Gautam840f4fe2013-04-16 16:50:30 +05301989 dcp = ((mdwc->charger.chg_type == DWC3_DCP_CHARGER) ||
Vijayavardhan Vennapusac4974862013-07-23 17:36:37 +05301990 (mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
1991 (mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05301992 host_bus_suspend = mdwc->host_mode == 1;
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301993
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05301994 if (mdwc->lpm_flags & MDWC3_TCXO_SHUTDOWN) {
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301995 /* Vote for TCXO while waking up USB HSPHY */
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05301996 ret = clk_prepare_enable(mdwc->xo_clk);
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05301997 if (ret)
1998 dev_err(mdwc->dev, "%s failed to vote TCXO buffer%d\n",
1999 __func__, ret);
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05302000 mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
Vijayavardhan Vennapusa98bccc52013-01-24 13:07:34 +05302001 }
2002
Hemant Kumar086bf6b2013-06-10 19:29:27 -07002003 /* add vote for controller power collapse */
2004 if (!host_bus_suspend)
2005 dwc3_msm_config_gdsc(mdwc, 1);
2006
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05302007 if (!host_bus_suspend)
2008 clk_prepare_enable(mdwc->utmi_clk);
2009
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302010 if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability && !dcp &&
2011 !host_bus_suspend)
Jack Pham4b00e702013-07-03 17:10:36 -07002012 dwc3_hsusb_ldo_enable(mdwc, 1);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302013
Jack Pham4b00e702013-07-03 17:10:36 -07002014 dwc3_ssusb_ldo_enable(mdwc, 1);
2015 dwc3_ssusb_config_vddcx(mdwc, 1);
Jack Pham22698b82013-02-13 17:45:06 -08002016
Manu Gautam840f4fe2013-04-16 16:50:30 +05302017 if (!host_bus_suspend && !dcp)
Jack Pham4b00e702013-07-03 17:10:36 -07002018 dwc3_hsusb_config_vddcx(mdwc, 1);
Jack Pham22698b82013-02-13 17:45:06 -08002019
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302020 if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
2021 clk_prepare_enable(mdwc->ref_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05302022 usleep_range(1000, 1200);
2023
Manu Gautam3e9ad352012-08-16 14:44:47 -07002024 clk_prepare_enable(mdwc->iface_clk);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302025 if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF) {
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05302026 clk_prepare_enable(mdwc->core_clk);
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302027 mdwc->lpm_flags &= ~MDWC3_PHY_REF_AND_CORECLK_OFF;
Vijayavardhan Vennapusaa00a5062013-04-19 12:31:07 +05302028 }
Manu Gautam377821c2012-09-28 16:53:24 +05302029
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302030 if (host_bus_suspend) {
2031 /* Disable HV interrupt */
2032 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
2033 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
2034 0x18000, 0x0);
2035 /* Clear interrupt latch register */
2036 dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0x000);
Manu Gautam377821c2012-09-28 16:53:24 +05302037
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302038 /* Disable DP and DM HV interrupt */
2039 dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302040 } else {
2041 /* Disable HV interrupt */
2042 if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
2043 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG,
2044 0x18000, 0x0);
2045 /* Disable Retention */
2046 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0x2, 0x2);
2047
2048 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
2049 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) |
2050 0xF0000000);
2051 /* 10usec delay required before de-asserting PHY RESET */
2052 udelay(10);
2053 dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0),
2054 dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) &
2055 0x7FFFFFFF);
2056
2057 /* Bring PHY out of suspend */
2058 dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, 0xC00000,
2059 0x0);
2060
2061 }
Manu Gautamb5067272012-07-02 09:53:41 +05302062
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302063 if (resume_from_core_clk_off) {
2064 /* Assert SS PHY RESET */
2065 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302066 (1 << 7));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302067 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302068 (1 << 28));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302069 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302070 (1 << 8));
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302071 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
2072 0x0);
2073 /* 10usec delay required before de-asserting SS PHY RESET */
2074 udelay(10);
2075 dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
2076 0x0);
Vijayavardhan Vennapusa4188de22012-11-06 15:20:18 +05302077
Vijayavardhan Vennapusaba79f6b2013-07-30 13:39:52 +05302078 /*
2079 * Reinitilize SSPHY parameters as SS_PHY RESET will reset
2080 * the internal registers to default values.
2081 */
2082 dwc3_msm_ss_phy_reg_init(mdwc);
2083 }
Manu Gautamb5067272012-07-02 09:53:41 +05302084 atomic_set(&mdwc->in_lpm, 0);
Manu Gautam377821c2012-09-28 16:53:24 +05302085
2086 /* match disable_irq call from isr */
2087 if (mdwc->lpm_irq_seen && mdwc->hs_phy_irq) {
2088 enable_irq(mdwc->hs_phy_irq);
2089 mdwc->lpm_irq_seen = false;
2090 }
Manu Gautam840f4fe2013-04-16 16:50:30 +05302091 /* it must DCP disconnect, re-enable HS_PHY wakeup IRQ */
2092 if (mdwc->hs_phy_irq && dcp)
2093 enable_irq_wake(mdwc->hs_phy_irq);
Manu Gautam377821c2012-09-28 16:53:24 +05302094
Manu Gautamb5067272012-07-02 09:53:41 +05302095 dev_info(mdwc->dev, "DWC3 exited from low power mode\n");
2096
2097 return 0;
2098}
2099
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302100static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc)
2101{
2102 unsigned long t;
2103
2104 /*
2105 * Defer next cable connect event till external charger
2106 * detection is completed.
2107 */
2108
2109 if (mdwc->ext_chg_active && (mdwc->ext_xceiv.bsv ||
2110 !mdwc->ext_xceiv.id)) {
2111
2112 dev_dbg(mdwc->dev, "before ext chg wait\n");
2113
2114 t = wait_for_completion_timeout(&mdwc->ext_chg_wait,
2115 msecs_to_jiffies(3000));
2116 if (!t)
2117 dev_err(mdwc->dev, "ext chg wait timeout\n");
2118 else
2119 dev_dbg(mdwc->dev, "ext chg wait done\n");
2120 }
2121
2122}
2123
Manu Gautamb5067272012-07-02 09:53:41 +05302124static void dwc3_resume_work(struct work_struct *w)
2125{
2126 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
2127 resume_work.work);
2128
2129 dev_dbg(mdwc->dev, "%s: dwc3 resume work\n", __func__);
2130 /* handle any event that was queued while work was already running */
2131 if (!atomic_read(&mdwc->in_lpm)) {
2132 dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302133 if (mdwc->otg_xceiv) {
2134 dwc3_wait_for_ext_chg_done(mdwc);
Manu Gautamb5067272012-07-02 09:53:41 +05302135 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2136 DWC3_EVENT_XCEIV_STATE);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302137 }
Manu Gautamb5067272012-07-02 09:53:41 +05302138 return;
2139 }
2140
2141 /* bail out if system resume in process, else initiate RESUME */
2142 if (atomic_read(&mdwc->pm_suspended)) {
2143 mdwc->resume_pending = true;
2144 } else {
2145 pm_runtime_get_sync(mdwc->dev);
2146 if (mdwc->otg_xceiv)
2147 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2148 DWC3_EVENT_PHY_RESUME);
Manu Gautambb825d72013-03-12 16:25:42 +05302149 pm_runtime_put_noidle(mdwc->dev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302150 if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability)) {
2151 dwc3_wait_for_ext_chg_done(mdwc);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302152 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2153 DWC3_EVENT_XCEIV_STATE);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302154 }
Manu Gautamb5067272012-07-02 09:53:41 +05302155 }
2156}
2157
Jack Pham0fc12332012-11-19 13:14:22 -08002158static u32 debug_id = true, debug_bsv, debug_connect;
Manu Gautamb5067272012-07-02 09:53:41 +05302159
2160static int dwc3_connect_show(struct seq_file *s, void *unused)
2161{
2162 if (debug_connect)
2163 seq_printf(s, "true\n");
2164 else
2165 seq_printf(s, "false\n");
2166
2167 return 0;
2168}
2169
2170static int dwc3_connect_open(struct inode *inode, struct file *file)
2171{
2172 return single_open(file, dwc3_connect_show, inode->i_private);
2173}
2174
2175static ssize_t dwc3_connect_write(struct file *file, const char __user *ubuf,
2176 size_t count, loff_t *ppos)
2177{
2178 struct seq_file *s = file->private_data;
2179 struct dwc3_msm *mdwc = s->private;
2180 char buf[8];
2181
2182 memset(buf, 0x00, sizeof(buf));
2183
2184 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
2185 return -EFAULT;
2186
2187 if (!strncmp(buf, "enable", 6) || !strncmp(buf, "true", 4)) {
2188 debug_connect = true;
2189 } else {
2190 debug_connect = debug_bsv = false;
2191 debug_id = true;
2192 }
2193
2194 mdwc->ext_xceiv.bsv = debug_bsv;
2195 mdwc->ext_xceiv.id = debug_id ? DWC3_ID_FLOAT : DWC3_ID_GROUND;
2196
2197 if (atomic_read(&mdwc->in_lpm)) {
2198 dev_dbg(mdwc->dev, "%s: calling resume_work\n", __func__);
2199 dwc3_resume_work(&mdwc->resume_work.work);
2200 } else {
2201 dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
2202 if (mdwc->otg_xceiv)
2203 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
2204 DWC3_EVENT_XCEIV_STATE);
2205 }
2206
2207 return count;
2208}
2209
2210const struct file_operations dwc3_connect_fops = {
2211 .open = dwc3_connect_open,
2212 .read = seq_read,
2213 .write = dwc3_connect_write,
2214 .llseek = seq_lseek,
2215 .release = single_release,
2216};
2217
2218static struct dentry *dwc3_debugfs_root;
2219
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05302220static void dwc3_msm_debugfs_init(struct dwc3_msm *mdwc)
Manu Gautamb5067272012-07-02 09:53:41 +05302221{
2222 dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
2223
2224 if (!dwc3_debugfs_root || IS_ERR(dwc3_debugfs_root))
2225 return;
2226
2227 if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
Vijayavardhan Vennapusa54be1d62012-10-06 18:32:06 +05302228 &debug_id))
Manu Gautamb5067272012-07-02 09:53:41 +05302229 goto error;
2230
2231 if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
Vijayavardhan Vennapusa54be1d62012-10-06 18:32:06 +05302232 &debug_bsv))
Manu Gautamb5067272012-07-02 09:53:41 +05302233 goto error;
2234
2235 if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
2236 dwc3_debugfs_root, mdwc, &dwc3_connect_fops))
2237 goto error;
2238
2239 return;
2240
2241error:
2242 debugfs_remove_recursive(dwc3_debugfs_root);
2243}
Manu Gautam8c642812012-06-07 10:35:10 +05302244
Manu Gautam377821c2012-09-28 16:53:24 +05302245static irqreturn_t msm_dwc3_irq(int irq, void *data)
2246{
2247 struct dwc3_msm *mdwc = data;
2248
2249 if (atomic_read(&mdwc->in_lpm)) {
2250 dev_dbg(mdwc->dev, "%s received in LPM\n", __func__);
2251 mdwc->lpm_irq_seen = true;
2252 disable_irq_nosync(irq);
2253 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
2254 } else {
2255 pr_info_ratelimited("%s: IRQ outside LPM\n", __func__);
2256 }
2257
2258 return IRQ_HANDLED;
2259}
2260
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302261static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
2262 enum power_supply_property psp,
2263 union power_supply_propval *val)
2264{
2265 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
2266 usb_psy);
2267 switch (psp) {
2268 case POWER_SUPPLY_PROP_SCOPE:
2269 val->intval = mdwc->host_mode;
2270 break;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302271 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2272 val->intval = mdwc->voltage_max;
2273 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302274 case POWER_SUPPLY_PROP_CURRENT_MAX:
2275 val->intval = mdwc->current_max;
2276 break;
2277 case POWER_SUPPLY_PROP_PRESENT:
2278 val->intval = mdwc->vbus_active;
2279 break;
2280 case POWER_SUPPLY_PROP_ONLINE:
2281 val->intval = mdwc->online;
2282 break;
Manu Gautamfa40cae2013-03-01 16:37:12 +05302283 case POWER_SUPPLY_PROP_TYPE:
2284 val->intval = psy->type;
2285 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302286 default:
2287 return -EINVAL;
2288 }
2289 return 0;
2290}
2291
2292static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
2293 enum power_supply_property psp,
2294 const union power_supply_propval *val)
2295{
2296 static bool init;
2297 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
2298 usb_psy);
2299
2300 switch (psp) {
2301 case POWER_SUPPLY_PROP_SCOPE:
2302 mdwc->host_mode = val->intval;
2303 break;
2304 /* Process PMIC notification in PRESENT prop */
2305 case POWER_SUPPLY_PROP_PRESENT:
2306 dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
Jack Pham9354c6a2012-12-20 19:19:32 -08002307 if (mdwc->otg_xceiv && !mdwc->ext_inuse &&
2308 (mdwc->ext_xceiv.otg_capability || !init)) {
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302309 mdwc->ext_xceiv.bsv = val->intval;
Vijayavardhan Vennapusa47786ef2013-11-11 13:03:19 +05302310 /*
2311 * set debouncing delay to 120msec. Otherwise battery
2312 * charging CDP complaince test fails if delay > 120ms.
2313 */
Manu Gautamf71d9cb2013-02-07 13:52:12 +05302314 queue_delayed_work(system_nrt_wq,
Vijayavardhan Vennapusa47786ef2013-11-11 13:03:19 +05302315 &mdwc->resume_work, 12);
Jack Pham9354c6a2012-12-20 19:19:32 -08002316
2317 if (!init)
2318 init = true;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302319 }
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302320 mdwc->vbus_active = val->intval;
2321 break;
2322 case POWER_SUPPLY_PROP_ONLINE:
2323 mdwc->online = val->intval;
2324 break;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302325 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2326 mdwc->voltage_max = val->intval;
2327 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302328 case POWER_SUPPLY_PROP_CURRENT_MAX:
2329 mdwc->current_max = val->intval;
2330 break;
Manu Gautamfa40cae2013-03-01 16:37:12 +05302331 case POWER_SUPPLY_PROP_TYPE:
2332 psy->type = val->intval;
2333 break;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302334 default:
2335 return -EINVAL;
2336 }
2337
2338 power_supply_changed(&mdwc->usb_psy);
2339 return 0;
2340}
2341
Jack Pham9354c6a2012-12-20 19:19:32 -08002342static void dwc3_msm_external_power_changed(struct power_supply *psy)
2343{
2344 struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm, usb_psy);
2345 union power_supply_propval ret = {0,};
2346
2347 if (!mdwc->ext_vbus_psy)
2348 mdwc->ext_vbus_psy = power_supply_get_by_name("ext-vbus");
2349
2350 if (!mdwc->ext_vbus_psy) {
2351 pr_err("%s: Unable to get ext_vbus power_supply\n", __func__);
2352 return;
2353 }
2354
2355 mdwc->ext_vbus_psy->get_property(mdwc->ext_vbus_psy,
2356 POWER_SUPPLY_PROP_ONLINE, &ret);
2357 if (ret.intval) {
2358 dwc3_start_chg_det(&mdwc->charger, false);
2359 mdwc->ext_vbus_psy->get_property(mdwc->ext_vbus_psy,
2360 POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
2361 power_supply_set_current_limit(&mdwc->usb_psy, ret.intval);
2362 }
2363
2364 power_supply_set_online(&mdwc->usb_psy, ret.intval);
2365 power_supply_changed(&mdwc->usb_psy);
2366}
2367
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302368static int
2369dwc3_msm_property_is_writeable(struct power_supply *psy,
2370 enum power_supply_property psp)
2371{
2372 switch (psp) {
2373 case POWER_SUPPLY_PROP_VOLTAGE_MAX:
2374 return 1;
2375 default:
2376 break;
2377 }
2378
2379 return 0;
2380}
2381
Jack Pham9354c6a2012-12-20 19:19:32 -08002382
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302383static char *dwc3_msm_pm_power_supplied_to[] = {
2384 "battery",
2385};
2386
2387static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
2388 POWER_SUPPLY_PROP_PRESENT,
2389 POWER_SUPPLY_PROP_ONLINE,
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05302390 POWER_SUPPLY_PROP_VOLTAGE_MAX,
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302391 POWER_SUPPLY_PROP_CURRENT_MAX,
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302392 POWER_SUPPLY_PROP_TYPE,
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302393 POWER_SUPPLY_PROP_SCOPE,
2394};
2395
Jack Phamfadd6432012-12-07 19:03:41 -08002396static void dwc3_init_adc_work(struct work_struct *w);
2397
Jack Phamb7209152013-07-03 17:04:53 -07002398static void dwc3_ext_notify_online(void *ctx, int on)
Jack Phamfadd6432012-12-07 19:03:41 -08002399{
Jack Phamb7209152013-07-03 17:04:53 -07002400 struct dwc3_msm *mdwc = ctx;
Jack Phamf12b7e12012-12-28 14:27:26 -08002401 bool notify_otg = false;
Jack Phamfadd6432012-12-07 19:03:41 -08002402
2403 if (!mdwc) {
2404 pr_err("%s: DWC3 driver already removed\n", __func__);
2405 return;
2406 }
2407
2408 dev_dbg(mdwc->dev, "notify %s%s\n", on ? "" : "dis", "connected");
2409
Jack Pham9354c6a2012-12-20 19:19:32 -08002410 if (!mdwc->ext_vbus_psy)
2411 mdwc->ext_vbus_psy = power_supply_get_by_name("ext-vbus");
2412
2413 mdwc->ext_inuse = on;
Jack Phamf12b7e12012-12-28 14:27:26 -08002414 if (on) {
2415 /* force OTG to exit B-peripheral state */
2416 mdwc->ext_xceiv.bsv = false;
2417 notify_otg = true;
Jack Pham9354c6a2012-12-20 19:19:32 -08002418 dwc3_start_chg_det(&mdwc->charger, false);
Jack Phamf12b7e12012-12-28 14:27:26 -08002419 } else {
2420 /* external client offline; tell OTG about cached ID/BSV */
2421 if (mdwc->ext_xceiv.id != mdwc->id_state) {
2422 mdwc->ext_xceiv.id = mdwc->id_state;
2423 notify_otg = true;
2424 }
2425
2426 mdwc->ext_xceiv.bsv = mdwc->vbus_active;
2427 notify_otg |= mdwc->vbus_active;
2428 }
Jack Pham9354c6a2012-12-20 19:19:32 -08002429
2430 if (mdwc->ext_vbus_psy)
2431 power_supply_set_present(mdwc->ext_vbus_psy, on);
Jack Phamf12b7e12012-12-28 14:27:26 -08002432
2433 if (notify_otg)
2434 queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
Jack Phamfadd6432012-12-07 19:03:41 -08002435}
2436
Jack Pham0cca9412013-03-08 13:22:42 -08002437static void dwc3_id_work(struct work_struct *w)
Jack Phamfadd6432012-12-07 19:03:41 -08002438{
Jack Pham0cca9412013-03-08 13:22:42 -08002439 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, id_work);
Jack Pham5c585062013-03-25 18:39:12 -07002440 int ret;
Jack Phamfadd6432012-12-07 19:03:41 -08002441
Jack Pham0cca9412013-03-08 13:22:42 -08002442 /* Give external client a chance to handle */
Jack Pham5c585062013-03-25 18:39:12 -07002443 if (!mdwc->ext_inuse && usb_ext) {
2444 if (mdwc->pmic_id_irq)
2445 disable_irq(mdwc->pmic_id_irq);
2446
2447 ret = usb_ext->notify(usb_ext->ctxt, mdwc->id_state,
Jack Phamb7209152013-07-03 17:04:53 -07002448 dwc3_ext_notify_online, mdwc);
Jack Pham5c585062013-03-25 18:39:12 -07002449 dev_dbg(mdwc->dev, "%s: external handler returned %d\n",
2450 __func__, ret);
2451
2452 if (mdwc->pmic_id_irq) {
Vijayavardhan Vennapusa242eaf02013-07-01 12:39:31 +05302453 unsigned long flags;
2454 local_irq_save(flags);
Jack Pham5c585062013-03-25 18:39:12 -07002455 /* ID may have changed while IRQ disabled; update it */
2456 mdwc->id_state = !!irq_read_line(mdwc->pmic_id_irq);
Vijayavardhan Vennapusa242eaf02013-07-01 12:39:31 +05302457 local_irq_restore(flags);
Jack Pham5c585062013-03-25 18:39:12 -07002458 enable_irq(mdwc->pmic_id_irq);
Jack Pham0cca9412013-03-08 13:22:42 -08002459 }
Jack Pham5c585062013-03-25 18:39:12 -07002460
2461 mdwc->ext_inuse = (ret == 0);
Jack Pham0cca9412013-03-08 13:22:42 -08002462 }
Jack Phamfadd6432012-12-07 19:03:41 -08002463
Jack Pham0cca9412013-03-08 13:22:42 -08002464 if (!mdwc->ext_inuse) { /* notify OTG */
2465 mdwc->ext_xceiv.id = mdwc->id_state;
2466 dwc3_resume_work(&mdwc->resume_work.work);
2467 }
2468}
2469
2470static irqreturn_t dwc3_pmic_id_irq(int irq, void *data)
2471{
2472 struct dwc3_msm *mdwc = data;
Jack Pham5c585062013-03-25 18:39:12 -07002473 enum dwc3_id_state id;
Jack Pham0cca9412013-03-08 13:22:42 -08002474
2475 /* If we can't read ID line state for some reason, treat it as float */
Jack Pham5c585062013-03-25 18:39:12 -07002476 id = !!irq_read_line(irq);
2477 if (mdwc->id_state != id) {
2478 mdwc->id_state = id;
2479 queue_work(system_nrt_wq, &mdwc->id_work);
2480 }
Jack Pham0cca9412013-03-08 13:22:42 -08002481
2482 return IRQ_HANDLED;
Jack Phamfadd6432012-12-07 19:03:41 -08002483}
2484
Jack Pham0fc12332012-11-19 13:14:22 -08002485static void dwc3_adc_notification(enum qpnp_tm_state state, void *ctx)
2486{
2487 struct dwc3_msm *mdwc = ctx;
2488
2489 if (state >= ADC_TM_STATE_NUM) {
2490 pr_err("%s: invalid notification %d\n", __func__, state);
2491 return;
2492 }
2493
2494 dev_dbg(mdwc->dev, "%s: state = %s\n", __func__,
2495 state == ADC_TM_HIGH_STATE ? "high" : "low");
2496
Jack Phamf12b7e12012-12-28 14:27:26 -08002497 /* save ID state, but don't necessarily notify OTG */
Jack Pham0fc12332012-11-19 13:14:22 -08002498 if (state == ADC_TM_HIGH_STATE) {
Jack Phamf12b7e12012-12-28 14:27:26 -08002499 mdwc->id_state = DWC3_ID_FLOAT;
Jack Pham0fc12332012-11-19 13:14:22 -08002500 mdwc->adc_param.state_request = ADC_TM_LOW_THR_ENABLE;
2501 } else {
Jack Phamf12b7e12012-12-28 14:27:26 -08002502 mdwc->id_state = DWC3_ID_GROUND;
Jack Pham0fc12332012-11-19 13:14:22 -08002503 mdwc->adc_param.state_request = ADC_TM_HIGH_THR_ENABLE;
2504 }
2505
Jack Pham0cca9412013-03-08 13:22:42 -08002506 dwc3_id_work(&mdwc->id_work);
2507
Jack Phamfadd6432012-12-07 19:03:41 -08002508 /* re-arm ADC interrupt */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002509 qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
Jack Pham0fc12332012-11-19 13:14:22 -08002510}
2511
2512static void dwc3_init_adc_work(struct work_struct *w)
2513{
2514 struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
2515 init_adc_work.work);
2516 int ret;
2517
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002518 mdwc->adc_tm_dev = qpnp_get_adc_tm(mdwc->dev, "dwc_usb3-adc_tm");
2519 if (IS_ERR(mdwc->adc_tm_dev)) {
2520 if (PTR_ERR(mdwc->adc_tm_dev) == -EPROBE_DEFER)
2521 queue_delayed_work(system_nrt_wq, to_delayed_work(w),
Jack Pham90b4d122012-12-13 11:46:22 -08002522 msecs_to_jiffies(100));
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002523 else
2524 mdwc->adc_tm_dev = NULL;
2525
Jack Pham0fc12332012-11-19 13:14:22 -08002526 return;
2527 }
2528
2529 mdwc->adc_param.low_thr = adc_low_threshold;
2530 mdwc->adc_param.high_thr = adc_high_threshold;
2531 mdwc->adc_param.timer_interval = adc_meas_interval;
2532 mdwc->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08002533 mdwc->adc_param.btm_ctx = mdwc;
Jack Pham0fc12332012-11-19 13:14:22 -08002534 mdwc->adc_param.threshold_notification = dwc3_adc_notification;
2535
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002536 ret = qpnp_adc_tm_usbid_configure(mdwc->adc_tm_dev, &mdwc->adc_param);
Jack Pham0fc12332012-11-19 13:14:22 -08002537 if (ret) {
2538 dev_err(mdwc->dev, "%s: request ADC error %d\n", __func__, ret);
2539 return;
2540 }
2541
2542 mdwc->id_adc_detect = true;
2543}
2544
2545static ssize_t adc_enable_show(struct device *dev,
2546 struct device_attribute *attr, char *buf)
2547{
Jack Pham84fc1ac2013-07-09 17:51:41 -07002548 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
2549
2550 if (!mdwc)
2551 return -EINVAL;
2552
2553 return snprintf(buf, PAGE_SIZE, "%s\n", mdwc->id_adc_detect ?
Jack Pham0fc12332012-11-19 13:14:22 -08002554 "enabled" : "disabled");
2555}
2556
2557static ssize_t adc_enable_store(struct device *dev,
2558 struct device_attribute *attr, const char
2559 *buf, size_t size)
2560{
Jack Pham84fc1ac2013-07-09 17:51:41 -07002561 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
2562
2563 if (!mdwc)
2564 return -EINVAL;
2565
Jack Pham0fc12332012-11-19 13:14:22 -08002566 if (!strnicmp(buf, "enable", 6)) {
Jack Pham84fc1ac2013-07-09 17:51:41 -07002567 if (!mdwc->id_adc_detect)
2568 dwc3_init_adc_work(&mdwc->init_adc_work.work);
Jack Pham0fc12332012-11-19 13:14:22 -08002569 return size;
2570 } else if (!strnicmp(buf, "disable", 7)) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07002571 qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
Jack Pham84fc1ac2013-07-09 17:51:41 -07002572 mdwc->id_adc_detect = false;
Jack Pham0fc12332012-11-19 13:14:22 -08002573 return size;
2574 }
2575
2576 return -EINVAL;
2577}
2578
2579static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
2580 adc_enable_store);
2581
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302582static int dwc3_msm_ext_chg_open(struct inode *inode, struct file *file)
2583{
Jack Phamea382b72013-07-09 17:50:20 -07002584 struct dwc3_msm *mdwc =
2585 container_of(inode->i_cdev, struct dwc3_msm, ext_chg_cdev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302586
2587 pr_debug("dwc3-msm ext chg open\n");
Jack Phamea382b72013-07-09 17:50:20 -07002588 file->private_data = mdwc;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302589 mdwc->ext_chg_opened = true;
Jack Phamea382b72013-07-09 17:50:20 -07002590
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302591 return 0;
2592}
2593
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302594static long
2595dwc3_msm_ext_chg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302596{
Jack Phamea382b72013-07-09 17:50:20 -07002597 struct dwc3_msm *mdwc = file->private_data;
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302598 struct msm_usb_chg_info info = {0};
2599 int ret = 0, val;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302600
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302601 switch (cmd) {
2602 case MSM_USB_EXT_CHG_INFO:
2603 info.chg_block_type = USB_CHG_BLOCK_QSCRATCH;
Jack Phamea382b72013-07-09 17:50:20 -07002604 info.page_offset = (mdwc->io_res->start +
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302605 QSCRATCH_REG_OFFSET) & ~PAGE_MASK;
2606 /*
2607 * The charger block register address space is only
2608 * 512 bytes. But mmap() works on PAGE granularity.
2609 */
2610 info.length = PAGE_SIZE;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302611
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302612 if (copy_to_user((void __user *)arg, &info, sizeof(info))) {
2613 pr_err("%s: copy to user failed\n\n", __func__);
2614 ret = -EFAULT;
2615 }
2616 break;
2617 case MSM_USB_EXT_CHG_BLOCK_LPM:
2618 if (get_user(val, (int __user *)arg)) {
2619 pr_err("%s: get_user failed\n\n", __func__);
2620 ret = -EFAULT;
2621 break;
2622 }
2623 pr_debug("%s: LPM block request %d\n", __func__, val);
2624 if (val) { /* block LPM */
2625 if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
2626 pm_runtime_get_sync(mdwc->dev);
2627 } else {
2628 mdwc->ext_chg_active = false;
2629 complete(&mdwc->ext_chg_wait);
2630 ret = -ENODEV;
2631 }
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302632 } else {
2633 mdwc->ext_chg_active = false;
2634 complete(&mdwc->ext_chg_wait);
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302635 pm_runtime_put(mdwc->dev);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302636 }
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302637 break;
2638 default:
2639 ret = -EINVAL;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302640 }
2641
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302642 return ret;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302643}
2644
2645static int dwc3_msm_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
2646{
Jack Phamea382b72013-07-09 17:50:20 -07002647 struct dwc3_msm *mdwc = file->private_data;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302648 unsigned long vsize = vma->vm_end - vma->vm_start;
2649 int ret;
2650
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302651 if (vma->vm_pgoff != 0 || vsize > PAGE_SIZE)
2652 return -EINVAL;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302653
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302654 vma->vm_pgoff = __phys_to_pfn(mdwc->io_res->start +
2655 QSCRATCH_REG_OFFSET);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302656 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
2657
2658 ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
2659 vsize, vma->vm_page_prot);
2660 if (ret < 0)
2661 pr_err("%s: failed with return val %d\n", __func__, ret);
2662
2663 return ret;
2664}
2665
2666static int dwc3_msm_ext_chg_release(struct inode *inode, struct file *file)
2667{
Jack Phamea382b72013-07-09 17:50:20 -07002668 struct dwc3_msm *mdwc = file->private_data;
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302669
2670 pr_debug("dwc3-msm ext chg release\n");
2671
2672 mdwc->ext_chg_opened = false;
2673
2674 return 0;
2675}
2676
2677static const struct file_operations dwc3_msm_ext_chg_fops = {
2678 .owner = THIS_MODULE,
2679 .open = dwc3_msm_ext_chg_open,
Pavankumar Kondeti17b52e72013-06-28 10:54:18 +05302680 .unlocked_ioctl = dwc3_msm_ext_chg_ioctl,
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05302681 .mmap = dwc3_msm_ext_chg_mmap,
2682 .release = dwc3_msm_ext_chg_release,
2683};
2684
2685static int dwc3_msm_setup_cdev(struct dwc3_msm *mdwc)
2686{
2687 int ret;
2688
2689 ret = alloc_chrdev_region(&mdwc->ext_chg_dev, 0, 1, "usb_ext_chg");
2690 if (ret < 0) {
2691 pr_err("Fail to allocate usb ext char dev region\n");
2692 return ret;
2693 }
2694 mdwc->ext_chg_class = class_create(THIS_MODULE, "dwc_ext_chg");
2695 if (ret < 0) {
2696 pr_err("Fail to create usb ext chg class\n");
2697 goto unreg_chrdev;
2698 }
2699 cdev_init(&mdwc->ext_chg_cdev, &dwc3_msm_ext_chg_fops);
2700 mdwc->ext_chg_cdev.owner = THIS_MODULE;
2701
2702 ret = cdev_add(&mdwc->ext_chg_cdev, mdwc->ext_chg_dev, 1);
2703 if (ret < 0) {
2704 pr_err("Fail to add usb ext chg cdev\n");
2705 goto destroy_class;
2706 }
2707 mdwc->ext_chg_device = device_create(mdwc->ext_chg_class,
2708 NULL, mdwc->ext_chg_dev, NULL,
2709 "usb_ext_chg");
2710 if (IS_ERR(mdwc->ext_chg_device)) {
2711 pr_err("Fail to create usb ext chg device\n");
2712 ret = PTR_ERR(mdwc->ext_chg_device);
2713 mdwc->ext_chg_device = NULL;
2714 goto del_cdev;
2715 }
2716
2717 pr_debug("dwc3 msm ext chg cdev setup success\n");
2718 return 0;
2719
2720del_cdev:
2721 cdev_del(&mdwc->ext_chg_cdev);
2722destroy_class:
2723 class_destroy(mdwc->ext_chg_class);
2724unreg_chrdev:
2725 unregister_chrdev_region(mdwc->ext_chg_dev, 1);
2726
2727 return ret;
2728}
2729
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002730static int __devinit dwc3_msm_probe(struct platform_device *pdev)
2731{
2732 struct device_node *node = pdev->dev.of_node;
Jack Pham80162462013-07-10 11:59:01 -07002733 struct dwc3_msm *mdwc;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002734 struct resource *res;
Ido Shayevitz7ad8ded2012-08-28 04:30:58 +03002735 void __iomem *tcsr;
Manu Gautamf08f7b62013-04-02 16:09:42 +05302736 unsigned long flags;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002737 int ret = 0;
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302738 int len = 0;
2739 u32 tmp[3];
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002740
Jack Pham80162462013-07-10 11:59:01 -07002741 mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL);
2742 if (!mdwc) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002743 dev_err(&pdev->dev, "not enough memory\n");
2744 return -ENOMEM;
2745 }
2746
Jack Pham80162462013-07-10 11:59:01 -07002747 platform_set_drvdata(pdev, mdwc);
2748 mdwc->dev = &pdev->dev;
Ido Shayevitz9fb83452012-04-01 17:45:58 +03002749
Jack Pham80162462013-07-10 11:59:01 -07002750 INIT_LIST_HEAD(&mdwc->req_complete_list);
2751 INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
2752 INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
2753 INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
Vijayavardhan Vennapusaddd04742013-09-26 19:47:18 +05302754 INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
Jack Pham80162462013-07-10 11:59:01 -07002755 INIT_WORK(&mdwc->id_work, dwc3_id_work);
2756 INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
2757 init_completion(&mdwc->ext_chg_wait);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02002758
Jack Pham80162462013-07-10 11:59:01 -07002759 ret = dwc3_msm_config_gdsc(mdwc, 1);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07002760 if (ret) {
2761 dev_err(&pdev->dev, "unable to configure usb3 gdsc\n");
2762 return ret;
2763 }
2764
Jack Pham80162462013-07-10 11:59:01 -07002765 mdwc->xo_clk = clk_get(&pdev->dev, "xo");
2766 if (IS_ERR(mdwc->xo_clk)) {
Manu Gautam377821c2012-09-28 16:53:24 +05302767 dev_err(&pdev->dev, "%s unable to get TCXO buffer handle\n",
2768 __func__);
Jack Pham80162462013-07-10 11:59:01 -07002769 ret = PTR_ERR(mdwc->xo_clk);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07002770 goto disable_dwc3_gdsc;
Manu Gautam377821c2012-09-28 16:53:24 +05302771 }
2772
Jack Pham80162462013-07-10 11:59:01 -07002773 ret = clk_prepare_enable(mdwc->xo_clk);
Manu Gautam377821c2012-09-28 16:53:24 +05302774 if (ret) {
2775 dev_err(&pdev->dev, "%s failed to vote for TCXO buffer%d\n",
2776 __func__, ret);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302777 goto put_xo;
Manu Gautam377821c2012-09-28 16:53:24 +05302778 }
2779
Manu Gautam1742db22012-06-19 13:33:24 +05302780 /*
2781 * DWC3 Core requires its CORE CLK (aka master / bus clk) to
2782 * run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
2783 */
Jack Pham80162462013-07-10 11:59:01 -07002784 mdwc->core_clk = devm_clk_get(&pdev->dev, "core_clk");
2785 if (IS_ERR(mdwc->core_clk)) {
Manu Gautam1742db22012-06-19 13:33:24 +05302786 dev_err(&pdev->dev, "failed to get core_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002787 ret = PTR_ERR(mdwc->core_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05302788 goto disable_xo;
Manu Gautam1742db22012-06-19 13:33:24 +05302789 }
Jack Pham80162462013-07-10 11:59:01 -07002790 clk_set_rate(mdwc->core_clk, 125000000);
2791 clk_prepare_enable(mdwc->core_clk);
Manu Gautam1742db22012-06-19 13:33:24 +05302792
Jack Pham80162462013-07-10 11:59:01 -07002793 mdwc->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
2794 if (IS_ERR(mdwc->iface_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002795 dev_err(&pdev->dev, "failed to get iface_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002796 ret = PTR_ERR(mdwc->iface_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002797 goto disable_core_clk;
2798 }
Jack Pham80162462013-07-10 11:59:01 -07002799 clk_prepare_enable(mdwc->iface_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002800
Jack Pham80162462013-07-10 11:59:01 -07002801 mdwc->sleep_clk = devm_clk_get(&pdev->dev, "sleep_clk");
2802 if (IS_ERR(mdwc->sleep_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002803 dev_err(&pdev->dev, "failed to get sleep_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002804 ret = PTR_ERR(mdwc->sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002805 goto disable_iface_clk;
2806 }
Jack Pham80162462013-07-10 11:59:01 -07002807 clk_prepare_enable(mdwc->sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002808
Jack Pham80162462013-07-10 11:59:01 -07002809 mdwc->hsphy_sleep_clk = devm_clk_get(&pdev->dev, "sleep_a_clk");
2810 if (IS_ERR(mdwc->hsphy_sleep_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002811 dev_err(&pdev->dev, "failed to get sleep_a_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002812 ret = PTR_ERR(mdwc->hsphy_sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002813 goto disable_sleep_clk;
2814 }
Jack Pham80162462013-07-10 11:59:01 -07002815 clk_prepare_enable(mdwc->hsphy_sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002816
Jack Pham80162462013-07-10 11:59:01 -07002817 mdwc->utmi_clk = devm_clk_get(&pdev->dev, "utmi_clk");
2818 if (IS_ERR(mdwc->utmi_clk)) {
Jack Pham22698b82013-02-13 17:45:06 -08002819 dev_err(&pdev->dev, "failed to get utmi_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002820 ret = PTR_ERR(mdwc->utmi_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002821 goto disable_sleep_a_clk;
2822 }
Jack Pham80162462013-07-10 11:59:01 -07002823 clk_prepare_enable(mdwc->utmi_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002824
Jack Pham80162462013-07-10 11:59:01 -07002825 mdwc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
2826 if (IS_ERR(mdwc->ref_clk)) {
Manu Gautam3e9ad352012-08-16 14:44:47 -07002827 dev_err(&pdev->dev, "failed to get ref_clk\n");
Jack Pham80162462013-07-10 11:59:01 -07002828 ret = PTR_ERR(mdwc->ref_clk);
Jack Pham22698b82013-02-13 17:45:06 -08002829 goto disable_utmi_clk;
Manu Gautam3e9ad352012-08-16 14:44:47 -07002830 }
Jack Pham80162462013-07-10 11:59:01 -07002831 clk_prepare_enable(mdwc->ref_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07002832
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302833 of_get_property(node, "qcom,vdd-voltage-level", &len);
2834 if (len == sizeof(tmp)) {
2835 of_property_read_u32_array(node, "qcom,vdd-voltage-level",
2836 tmp, len/sizeof(*tmp));
Jack Pham80162462013-07-10 11:59:01 -07002837 mdwc->vdd_no_vol_level = tmp[0];
2838 mdwc->vdd_low_vol_level = tmp[1];
2839 mdwc->vdd_high_vol_level = tmp[2];
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302840 } else {
2841 dev_err(&pdev->dev, "no qcom,vdd-voltage-level property\n");
2842 ret = -EINVAL;
2843 goto disable_ref_clk;
2844 }
2845
Manu Gautam60e01352012-05-29 09:00:34 +05302846 /* SS PHY */
Jack Pham80162462013-07-10 11:59:01 -07002847 mdwc->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
2848 if (IS_ERR(mdwc->ssusb_vddcx)) {
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302849 dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
Jack Pham80162462013-07-10 11:59:01 -07002850 ret = PTR_ERR(mdwc->ssusb_vddcx);
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302851 goto disable_ref_clk;
Manu Gautam60e01352012-05-29 09:00:34 +05302852 }
2853
Jack Pham80162462013-07-10 11:59:01 -07002854 ret = dwc3_ssusb_config_vddcx(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302855 if (ret) {
2856 dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
Manu Gautam3e9ad352012-08-16 14:44:47 -07002857 goto disable_ref_clk;
Manu Gautam60e01352012-05-29 09:00:34 +05302858 }
2859
Jack Pham80162462013-07-10 11:59:01 -07002860 ret = regulator_enable(mdwc->ssusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05302861 if (ret) {
2862 dev_err(&pdev->dev, "unable to enable the ssusb vddcx\n");
2863 goto unconfig_ss_vddcx;
2864 }
2865
Jack Pham80162462013-07-10 11:59:01 -07002866 ret = dwc3_ssusb_ldo_init(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302867 if (ret) {
2868 dev_err(&pdev->dev, "ssusb vreg configuration failed\n");
2869 goto disable_ss_vddcx;
2870 }
2871
Jack Pham80162462013-07-10 11:59:01 -07002872 ret = dwc3_ssusb_ldo_enable(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302873 if (ret) {
2874 dev_err(&pdev->dev, "ssusb vreg enable failed\n");
2875 goto free_ss_ldo_init;
2876 }
2877
2878 /* HS PHY */
Jack Pham80162462013-07-10 11:59:01 -07002879 mdwc->hsusb_vddcx = devm_regulator_get(&pdev->dev, "hsusb_vdd_dig");
2880 if (IS_ERR(mdwc->hsusb_vddcx)) {
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302881 dev_err(&pdev->dev, "unable to get hsusb vddcx\n");
Jack Pham80162462013-07-10 11:59:01 -07002882 ret = PTR_ERR(mdwc->hsusb_vddcx);
Vijayavardhan Vennapusa993798a2012-11-09 15:11:21 +05302883 goto disable_ss_ldo;
Manu Gautam60e01352012-05-29 09:00:34 +05302884 }
2885
Jack Pham80162462013-07-10 11:59:01 -07002886 ret = dwc3_hsusb_config_vddcx(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302887 if (ret) {
2888 dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
2889 goto disable_ss_ldo;
2890 }
2891
Jack Pham80162462013-07-10 11:59:01 -07002892 ret = regulator_enable(mdwc->hsusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05302893 if (ret) {
2894 dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
2895 goto unconfig_hs_vddcx;
2896 }
2897
Jack Pham80162462013-07-10 11:59:01 -07002898 ret = dwc3_hsusb_ldo_init(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302899 if (ret) {
2900 dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
2901 goto disable_hs_vddcx;
2902 }
2903
Jack Pham80162462013-07-10 11:59:01 -07002904 ret = dwc3_hsusb_ldo_enable(mdwc, 1);
Manu Gautam60e01352012-05-29 09:00:34 +05302905 if (ret) {
2906 dev_err(&pdev->dev, "hsusb vreg enable failed\n");
2907 goto free_hs_ldo_init;
2908 }
2909
Jack Pham80162462013-07-10 11:59:01 -07002910 mdwc->id_state = mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
2911 mdwc->ext_xceiv.otg_capability = of_property_read_bool(node,
Manu Gautam6c0ff032012-11-02 14:55:35 +05302912 "qcom,otg-capability");
Jack Pham80162462013-07-10 11:59:01 -07002913 mdwc->charger.charging_disabled = of_property_read_bool(node,
Manu Gautam6c0ff032012-11-02 14:55:35 +05302914 "qcom,charging-disabled");
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05302915
Jack Pham80162462013-07-10 11:59:01 -07002916 mdwc->charger.skip_chg_detect = of_property_read_bool(node,
Hemant Kumar6d7b7242013-04-18 16:44:38 -07002917 "qcom,skip-charger-detection");
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302918 /*
2919 * DWC3 has separate IRQ line for OTG events (ID/BSV) and for
2920 * DP and DM linestate transitions during low power mode.
2921 */
Jack Pham80162462013-07-10 11:59:01 -07002922 mdwc->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
2923 if (mdwc->hs_phy_irq < 0) {
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302924 dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
Jack Pham80162462013-07-10 11:59:01 -07002925 mdwc->hs_phy_irq = 0;
Jack Pham0fc12332012-11-19 13:14:22 -08002926 } else {
Jack Pham80162462013-07-10 11:59:01 -07002927 ret = devm_request_irq(&pdev->dev, mdwc->hs_phy_irq,
Jack Pham56a0a632013-03-08 13:18:42 -08002928 msm_dwc3_irq, IRQF_TRIGGER_RISING,
Jack Pham80162462013-07-10 11:59:01 -07002929 "msm_dwc3", mdwc);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302930 if (ret) {
2931 dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
2932 goto disable_hs_ldo;
2933 }
Jack Pham80162462013-07-10 11:59:01 -07002934 enable_irq_wake(mdwc->hs_phy_irq);
Vijayavardhan Vennapusa45145882013-01-03 14:11:58 +05302935 }
Jack Pham0cca9412013-03-08 13:22:42 -08002936
Jack Pham80162462013-07-10 11:59:01 -07002937 if (mdwc->ext_xceiv.otg_capability) {
2938 mdwc->pmic_id_irq =
2939 platform_get_irq_byname(pdev, "pmic_id_irq");
2940 if (mdwc->pmic_id_irq > 0) {
David Keitelad4a0282013-03-19 18:04:27 -07002941 /* check if PMIC ID IRQ is supported */
2942 ret = qpnp_misc_irqs_available(&pdev->dev);
2943
2944 if (ret == -EPROBE_DEFER) {
2945 /* qpnp hasn't probed yet; defer dwc probe */
Jack Pham0cca9412013-03-08 13:22:42 -08002946 goto disable_hs_ldo;
David Keitelad4a0282013-03-19 18:04:27 -07002947 } else if (ret == 0) {
Jack Pham80162462013-07-10 11:59:01 -07002948 mdwc->pmic_id_irq = 0;
David Keitelad4a0282013-03-19 18:04:27 -07002949 } else {
2950 ret = devm_request_irq(&pdev->dev,
Jack Pham80162462013-07-10 11:59:01 -07002951 mdwc->pmic_id_irq,
David Keitelad4a0282013-03-19 18:04:27 -07002952 dwc3_pmic_id_irq,
2953 IRQF_TRIGGER_RISING |
2954 IRQF_TRIGGER_FALLING,
Jack Pham80162462013-07-10 11:59:01 -07002955 "dwc3_msm_pmic_id",
2956 mdwc);
David Keitelad4a0282013-03-19 18:04:27 -07002957 if (ret) {
2958 dev_err(&pdev->dev, "irqreq IDINT failed\n");
2959 goto disable_hs_ldo;
2960 }
Jack Pham9198d9f2013-04-09 17:54:54 -07002961
Manu Gautamf08f7b62013-04-02 16:09:42 +05302962 local_irq_save(flags);
2963 /* Update initial ID state */
Jack Pham80162462013-07-10 11:59:01 -07002964 mdwc->id_state =
2965 !!irq_read_line(mdwc->pmic_id_irq);
2966 if (mdwc->id_state == DWC3_ID_GROUND)
Jack Pham9198d9f2013-04-09 17:54:54 -07002967 queue_work(system_nrt_wq,
Jack Pham80162462013-07-10 11:59:01 -07002968 &mdwc->id_work);
Manu Gautamf08f7b62013-04-02 16:09:42 +05302969 local_irq_restore(flags);
Jack Pham80162462013-07-10 11:59:01 -07002970 enable_irq_wake(mdwc->pmic_id_irq);
Jack Pham0cca9412013-03-08 13:22:42 -08002971 }
David Keitelad4a0282013-03-19 18:04:27 -07002972 }
2973
Jack Pham80162462013-07-10 11:59:01 -07002974 if (mdwc->pmic_id_irq <= 0) {
Jack Pham0cca9412013-03-08 13:22:42 -08002975 /* If no PMIC ID IRQ, use ADC for ID pin detection */
Jack Pham80162462013-07-10 11:59:01 -07002976 queue_work(system_nrt_wq, &mdwc->init_adc_work.work);
Jack Pham0cca9412013-03-08 13:22:42 -08002977 device_create_file(&pdev->dev, &dev_attr_adc_enable);
Jack Pham80162462013-07-10 11:59:01 -07002978 mdwc->pmic_id_irq = 0;
Jack Pham0cca9412013-03-08 13:22:42 -08002979 }
Manu Gautam377821c2012-09-28 16:53:24 +05302980 }
2981
Ido Shayevitz7ad8ded2012-08-28 04:30:58 +03002982 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2983 if (!res) {
2984 dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
2985 } else {
2986 tcsr = devm_ioremap_nocache(&pdev->dev, res->start,
2987 resource_size(res));
2988 if (!tcsr) {
2989 dev_dbg(&pdev->dev, "tcsr ioremap failed\n");
2990 } else {
2991 /* Enable USB3 on the primary USB port. */
2992 writel_relaxed(0x1, tcsr);
2993 /*
2994 * Ensure that TCSR write is completed before
2995 * USB registers initialization.
2996 */
2997 mb();
2998 }
2999 }
3000
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003001 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3002 if (!res) {
3003 dev_err(&pdev->dev, "missing memory base resource\n");
Manu Gautam60e01352012-05-29 09:00:34 +05303004 ret = -ENODEV;
Jack Pham56a0a632013-03-08 13:18:42 -08003005 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003006 }
3007
Jack Pham80162462013-07-10 11:59:01 -07003008 mdwc->base = devm_ioremap_nocache(&pdev->dev, res->start,
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003009 resource_size(res));
Jack Pham80162462013-07-10 11:59:01 -07003010 if (!mdwc->base) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003011 dev_err(&pdev->dev, "ioremap failed\n");
Manu Gautam60e01352012-05-29 09:00:34 +05303012 ret = -ENODEV;
Jack Pham56a0a632013-03-08 13:18:42 -08003013 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003014 }
3015
Jack Pham80162462013-07-10 11:59:01 -07003016 mdwc->io_res = res; /* used to calculate chg block offset */
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003017
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05303018 if (of_property_read_u32(node, "qcom,dwc-hsphy-init",
Jack Pham80162462013-07-10 11:59:01 -07003019 &mdwc->hsphy_init_seq))
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05303020 dev_dbg(&pdev->dev, "unable to read hsphy init seq\n");
Jack Pham80162462013-07-10 11:59:01 -07003021 else if (!mdwc->hsphy_init_seq)
Vijayavardhan Vennapusa26a49602012-12-18 13:51:45 +05303022 dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
3023
Vijayavardhan Vennapusa9f74b1b2013-09-23 19:22:17 +05303024 if (of_property_read_u32(node, "qcom,dwc-ssphy-deemphasis-value",
3025 &mdwc->deemphasis_val))
3026 dev_dbg(&pdev->dev, "unable to read ssphy deemphasis value\n");
3027
Jack Pham80162462013-07-10 11:59:01 -07003028 pm_runtime_set_active(mdwc->dev);
3029 pm_runtime_enable(mdwc->dev);
Manu Gautamb5067272012-07-02 09:53:41 +05303030
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003031 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
Jack Pham80162462013-07-10 11:59:01 -07003032 &mdwc->dbm_num_eps)) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003033 dev_err(&pdev->dev,
3034 "unable to read platform data num of dbm eps\n");
Jack Pham80162462013-07-10 11:59:01 -07003035 mdwc->dbm_num_eps = DBM_MAX_EPS;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003036 }
3037
Jack Pham80162462013-07-10 11:59:01 -07003038 if (mdwc->dbm_num_eps > DBM_MAX_EPS) {
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003039 dev_err(&pdev->dev,
3040 "Driver doesn't support number of DBM EPs. "
3041 "max: %d, dbm_num_eps: %d\n",
Jack Pham80162462013-07-10 11:59:01 -07003042 DBM_MAX_EPS, mdwc->dbm_num_eps);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003043 ret = -ENODEV;
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +05303044 goto disable_hs_ldo;
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003045 }
Vijayavardhan Vennapusafc3db602013-08-20 17:54:54 +05303046
3047 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-tx-fifo-size",
3048 &mdwc->tx_fifo_size))
3049 dev_err(&pdev->dev,
3050 "unable to read platform data tx fifo size\n");
3051
3052 if (of_property_read_u32(node, "qcom,dwc-usb3-msm-qdss-tx-fifo-size",
3053 &mdwc->qdss_tx_fifo_size))
3054 dev_err(&pdev->dev,
3055 "unable to read platform data qdss tx fifo size\n");
3056
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05303057 dwc3_set_notifier(&dwc3_msm_notify_event);
Manu Gautambb825d72013-03-12 16:25:42 +05303058 /* usb_psy required only for vbus_notifications or charging support */
Jack Pham80162462013-07-10 11:59:01 -07003059 if (mdwc->ext_xceiv.otg_capability ||
3060 !mdwc->charger.charging_disabled) {
3061 mdwc->usb_psy.name = "usb";
3062 mdwc->usb_psy.type = POWER_SUPPLY_TYPE_USB;
3063 mdwc->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
3064 mdwc->usb_psy.num_supplicants = ARRAY_SIZE(
Manu Gautambb825d72013-03-12 16:25:42 +05303065 dwc3_msm_pm_power_supplied_to);
Jack Pham80162462013-07-10 11:59:01 -07003066 mdwc->usb_psy.properties = dwc3_msm_pm_power_props_usb;
3067 mdwc->usb_psy.num_properties =
Manu Gautambb825d72013-03-12 16:25:42 +05303068 ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
Jack Pham80162462013-07-10 11:59:01 -07003069 mdwc->usb_psy.get_property = dwc3_msm_power_get_property_usb;
3070 mdwc->usb_psy.set_property = dwc3_msm_power_set_property_usb;
3071 mdwc->usb_psy.external_power_changed =
Manu Gautambb825d72013-03-12 16:25:42 +05303072 dwc3_msm_external_power_changed;
Pavankumar Kondetifbd4b142013-07-16 11:13:05 +05303073 mdwc->usb_psy.property_is_writeable =
3074 dwc3_msm_property_is_writeable;
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303075
Jack Pham80162462013-07-10 11:59:01 -07003076 ret = power_supply_register(&pdev->dev, &mdwc->usb_psy);
Manu Gautambb825d72013-03-12 16:25:42 +05303077 if (ret < 0) {
3078 dev_err(&pdev->dev,
3079 "%s:power_supply_register usb failed\n",
3080 __func__);
3081 goto disable_hs_ldo;
3082 }
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303083 }
3084
Vijayavardhan Vennapusa8eb68732013-03-26 13:05:38 +05303085 if (node) {
3086 ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
3087 if (ret) {
3088 dev_err(&pdev->dev,
3089 "failed to add create dwc3 core\n");
3090 goto put_psupply;
3091 }
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003092 }
3093
Jack Pham80162462013-07-10 11:59:01 -07003094 mdwc->bus_scale_table = msm_bus_cl_get_pdata(pdev);
3095 if (!mdwc->bus_scale_table) {
Manu Gautam2617deb2012-08-31 17:50:06 -07003096 dev_err(&pdev->dev, "bus scaling is disabled\n");
3097 } else {
Jack Pham80162462013-07-10 11:59:01 -07003098 mdwc->bus_perf_client =
3099 msm_bus_scale_register_client(mdwc->bus_scale_table);
Manu Gautam2617deb2012-08-31 17:50:06 -07003100 ret = msm_bus_scale_client_update_request(
Jack Pham80162462013-07-10 11:59:01 -07003101 mdwc->bus_perf_client, 1);
Manu Gautam2617deb2012-08-31 17:50:06 -07003102 if (ret)
3103 dev_err(&pdev->dev, "Failed to vote for bus scaling\n");
3104 }
3105
Jack Pham80162462013-07-10 11:59:01 -07003106 mdwc->otg_xceiv = usb_get_transceiver();
Manu Gautambb825d72013-03-12 16:25:42 +05303107 /* Register with OTG if present, ignore USB2 OTG using other PHY */
Jack Pham80162462013-07-10 11:59:01 -07003108 if (mdwc->otg_xceiv &&
3109 !(mdwc->otg_xceiv->flags & ENABLE_SECONDARY_PHY)) {
Hemant Kumar6d7b7242013-04-18 16:44:38 -07003110 /* Skip charger detection for simulator targets */
Jack Pham80162462013-07-10 11:59:01 -07003111 if (!mdwc->charger.skip_chg_detect) {
3112 mdwc->charger.start_detection = dwc3_start_chg_det;
3113 ret = dwc3_set_charger(mdwc->otg_xceiv->otg,
3114 &mdwc->charger);
3115 if (ret || !mdwc->charger.notify_detection_complete) {
Hemant Kumar6d7b7242013-04-18 16:44:38 -07003116 dev_err(&pdev->dev,
3117 "failed to register charger: %d\n",
3118 ret);
3119 goto put_xcvr;
3120 }
Manu Gautam8c642812012-06-07 10:35:10 +05303121 }
Manu Gautamb5067272012-07-02 09:53:41 +05303122
Jack Pham80162462013-07-10 11:59:01 -07003123 if (mdwc->ext_xceiv.otg_capability)
3124 mdwc->ext_xceiv.ext_block_reset = dwc3_msm_block_reset;
3125 ret = dwc3_set_ext_xceiv(mdwc->otg_xceiv->otg,
3126 &mdwc->ext_xceiv);
3127 if (ret || !mdwc->ext_xceiv.notify_ext_events) {
Manu Gautamb5067272012-07-02 09:53:41 +05303128 dev_err(&pdev->dev, "failed to register xceiver: %d\n",
3129 ret);
3130 goto put_xcvr;
3131 }
Manu Gautam8c642812012-06-07 10:35:10 +05303132 } else {
Manu Gautambb825d72013-03-12 16:25:42 +05303133 dev_dbg(&pdev->dev, "No OTG, DWC3 running in host only mode\n");
Jack Pham80162462013-07-10 11:59:01 -07003134 mdwc->host_mode = 1;
3135 mdwc->vbus_otg = devm_regulator_get(&pdev->dev, "vbus_dwc3");
3136 if (IS_ERR(mdwc->vbus_otg)) {
Manu Gautambb825d72013-03-12 16:25:42 +05303137 dev_dbg(&pdev->dev, "Failed to get vbus regulator\n");
Jack Pham80162462013-07-10 11:59:01 -07003138 mdwc->vbus_otg = 0;
Manu Gautambb825d72013-03-12 16:25:42 +05303139 } else {
Jack Pham80162462013-07-10 11:59:01 -07003140 ret = regulator_enable(mdwc->vbus_otg);
Manu Gautambb825d72013-03-12 16:25:42 +05303141 if (ret) {
Jack Pham80162462013-07-10 11:59:01 -07003142 mdwc->vbus_otg = 0;
Manu Gautambb825d72013-03-12 16:25:42 +05303143 dev_err(&pdev->dev, "Failed to enable vbus_otg\n");
3144 }
3145 }
Jack Pham80162462013-07-10 11:59:01 -07003146 mdwc->otg_xceiv = NULL;
Manu Gautam8c642812012-06-07 10:35:10 +05303147 }
Jack Pham80162462013-07-10 11:59:01 -07003148 if (mdwc->ext_xceiv.otg_capability && mdwc->charger.start_detection) {
3149 ret = dwc3_msm_setup_cdev(mdwc);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303150 if (ret)
3151 dev_err(&pdev->dev, "Fail to setup dwc3 setup cdev\n");
3152 }
Manu Gautam8c642812012-06-07 10:35:10 +05303153
Jack Pham80162462013-07-10 11:59:01 -07003154 device_init_wakeup(mdwc->dev, 1);
3155 pm_stay_awake(mdwc->dev);
Vijayavardhan Vennapusa8a011c92013-07-29 09:06:48 +05303156 dwc3_msm_debugfs_init(mdwc);
Manu Gautamb5067272012-07-02 09:53:41 +05303157
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003158 return 0;
3159
Manu Gautam8c642812012-06-07 10:35:10 +05303160put_xcvr:
Jack Pham80162462013-07-10 11:59:01 -07003161 usb_put_transceiver(mdwc->otg_xceiv);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303162put_psupply:
Jack Pham80162462013-07-10 11:59:01 -07003163 if (mdwc->usb_psy.dev)
3164 power_supply_unregister(&mdwc->usb_psy);
Manu Gautam60e01352012-05-29 09:00:34 +05303165disable_hs_ldo:
Jack Pham80162462013-07-10 11:59:01 -07003166 dwc3_hsusb_ldo_enable(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303167free_hs_ldo_init:
Jack Pham80162462013-07-10 11:59:01 -07003168 dwc3_hsusb_ldo_init(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303169disable_hs_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003170 regulator_disable(mdwc->hsusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05303171unconfig_hs_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003172 dwc3_hsusb_config_vddcx(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303173disable_ss_ldo:
Jack Pham80162462013-07-10 11:59:01 -07003174 dwc3_ssusb_ldo_enable(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303175free_ss_ldo_init:
Jack Pham80162462013-07-10 11:59:01 -07003176 dwc3_ssusb_ldo_init(mdwc, 0);
Manu Gautam60e01352012-05-29 09:00:34 +05303177disable_ss_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003178 regulator_disable(mdwc->ssusb_vddcx);
Manu Gautam60e01352012-05-29 09:00:34 +05303179unconfig_ss_vddcx:
Jack Pham80162462013-07-10 11:59:01 -07003180 dwc3_ssusb_config_vddcx(mdwc, 0);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003181disable_ref_clk:
Jack Pham80162462013-07-10 11:59:01 -07003182 clk_disable_unprepare(mdwc->ref_clk);
Jack Pham22698b82013-02-13 17:45:06 -08003183disable_utmi_clk:
Jack Pham80162462013-07-10 11:59:01 -07003184 clk_disable_unprepare(mdwc->utmi_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003185disable_sleep_a_clk:
Jack Pham80162462013-07-10 11:59:01 -07003186 clk_disable_unprepare(mdwc->hsphy_sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003187disable_sleep_clk:
Jack Pham80162462013-07-10 11:59:01 -07003188 clk_disable_unprepare(mdwc->sleep_clk);
Manu Gautam3e9ad352012-08-16 14:44:47 -07003189disable_iface_clk:
Jack Pham80162462013-07-10 11:59:01 -07003190 clk_disable_unprepare(mdwc->iface_clk);
Manu Gautam1742db22012-06-19 13:33:24 +05303191disable_core_clk:
Jack Pham80162462013-07-10 11:59:01 -07003192 clk_disable_unprepare(mdwc->core_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05303193disable_xo:
Jack Pham80162462013-07-10 11:59:01 -07003194 clk_disable_unprepare(mdwc->xo_clk);
Vijayavardhan Vennapusadec1fe62013-02-12 16:05:14 +05303195put_xo:
Jack Pham80162462013-07-10 11:59:01 -07003196 clk_put(mdwc->xo_clk);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07003197disable_dwc3_gdsc:
Jack Pham80162462013-07-10 11:59:01 -07003198 dwc3_msm_config_gdsc(mdwc, 0);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003199
3200 return ret;
3201}
3202
3203static int __devexit dwc3_msm_remove(struct platform_device *pdev)
3204{
Jack Pham80162462013-07-10 11:59:01 -07003205 struct dwc3_msm *mdwc = platform_get_drvdata(pdev);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003206
Jack Pham80162462013-07-10 11:59:01 -07003207 if (!mdwc->ext_chg_device) {
3208 device_destroy(mdwc->ext_chg_class, mdwc->ext_chg_dev);
3209 cdev_del(&mdwc->ext_chg_cdev);
3210 class_destroy(mdwc->ext_chg_class);
3211 unregister_chrdev_region(mdwc->ext_chg_dev, 1);
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303212 }
3213
Jack Pham80162462013-07-10 11:59:01 -07003214 if (mdwc->id_adc_detect)
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07003215 qpnp_adc_tm_usbid_end(mdwc->adc_tm_dev);
Manu Gautamb5067272012-07-02 09:53:41 +05303216 if (dwc3_debugfs_root)
3217 debugfs_remove_recursive(dwc3_debugfs_root);
Jack Pham80162462013-07-10 11:59:01 -07003218 if (mdwc->otg_xceiv) {
3219 dwc3_start_chg_det(&mdwc->charger, false);
3220 usb_put_transceiver(mdwc->otg_xceiv);
Manu Gautam8c642812012-06-07 10:35:10 +05303221 }
Jack Pham80162462013-07-10 11:59:01 -07003222 if (mdwc->usb_psy.dev)
3223 power_supply_unregister(&mdwc->usb_psy);
3224 if (mdwc->vbus_otg)
3225 regulator_disable(mdwc->vbus_otg);
Jack Pham0fc12332012-11-19 13:14:22 -08003226
Jack Pham80162462013-07-10 11:59:01 -07003227 pm_runtime_disable(mdwc->dev);
3228 device_init_wakeup(mdwc->dev, 0);
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003229
Jack Pham80162462013-07-10 11:59:01 -07003230 dwc3_hsusb_ldo_enable(mdwc, 0);
3231 dwc3_hsusb_ldo_init(mdwc, 0);
3232 regulator_disable(mdwc->hsusb_vddcx);
3233 dwc3_hsusb_config_vddcx(mdwc, 0);
3234 dwc3_ssusb_ldo_enable(mdwc, 0);
3235 dwc3_ssusb_ldo_init(mdwc, 0);
3236 regulator_disable(mdwc->ssusb_vddcx);
3237 dwc3_ssusb_config_vddcx(mdwc, 0);
3238 clk_disable_unprepare(mdwc->core_clk);
3239 clk_disable_unprepare(mdwc->iface_clk);
3240 clk_disable_unprepare(mdwc->sleep_clk);
3241 clk_disable_unprepare(mdwc->hsphy_sleep_clk);
3242 clk_disable_unprepare(mdwc->ref_clk);
3243 clk_disable_unprepare(mdwc->xo_clk);
3244 clk_put(mdwc->xo_clk);
Manu Gautam60e01352012-05-29 09:00:34 +05303245
Jack Pham80162462013-07-10 11:59:01 -07003246 dwc3_msm_config_gdsc(mdwc, 0);
Hemant Kumar086bf6b2013-06-10 19:29:27 -07003247
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003248 return 0;
3249}
3250
Manu Gautamb5067272012-07-02 09:53:41 +05303251static int dwc3_msm_pm_suspend(struct device *dev)
3252{
3253 int ret = 0;
3254 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3255
3256 dev_dbg(dev, "dwc3-msm PM suspend\n");
3257
Manu Gautam8d98a572013-01-21 16:34:50 +05303258 flush_delayed_work_sync(&mdwc->resume_work);
3259 if (!atomic_read(&mdwc->in_lpm)) {
3260 dev_err(mdwc->dev, "Abort PM suspend!! (USB is outside LPM)\n");
3261 return -EBUSY;
3262 }
3263
Manu Gautamb5067272012-07-02 09:53:41 +05303264 ret = dwc3_msm_suspend(mdwc);
3265 if (!ret)
3266 atomic_set(&mdwc->pm_suspended, 1);
3267
3268 return ret;
3269}
3270
3271static int dwc3_msm_pm_resume(struct device *dev)
3272{
3273 int ret = 0;
3274 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3275
3276 dev_dbg(dev, "dwc3-msm PM resume\n");
3277
3278 atomic_set(&mdwc->pm_suspended, 0);
3279 if (mdwc->resume_pending) {
3280 mdwc->resume_pending = false;
3281
3282 ret = dwc3_msm_resume(mdwc);
3283 /* Update runtime PM status */
3284 pm_runtime_disable(dev);
3285 pm_runtime_set_active(dev);
3286 pm_runtime_enable(dev);
3287
3288 /* Let OTG know about resume event and update pm_count */
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303289 if (mdwc->otg_xceiv) {
Manu Gautamb5067272012-07-02 09:53:41 +05303290 mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
3291 DWC3_EVENT_PHY_RESUME);
Vijayavardhan Vennapusad2993b82012-10-22 13:08:21 +05303292 if (mdwc->ext_xceiv.otg_capability)
3293 mdwc->ext_xceiv.notify_ext_events(
3294 mdwc->otg_xceiv->otg,
3295 DWC3_EVENT_XCEIV_STATE);
3296 }
Manu Gautamb5067272012-07-02 09:53:41 +05303297 }
3298
3299 return ret;
3300}
3301
3302static int dwc3_msm_runtime_idle(struct device *dev)
3303{
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303304 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3305
Manu Gautamb5067272012-07-02 09:53:41 +05303306 dev_dbg(dev, "DWC3-msm runtime idle\n");
3307
Pavankumar Kondeti08693e72013-05-03 11:55:48 +05303308 if (mdwc->ext_chg_active) {
3309 dev_dbg(dev, "Deferring LPM\n");
3310 /*
3311 * Charger detection may happen in user space.
3312 * Delay entering LPM by 3 sec. Otherwise we
3313 * have to exit LPM when user space begins
3314 * charger detection.
3315 *
3316 * This timer will be canceled when user space
3317 * votes against LPM by incrementing PM usage
3318 * counter. We enter low power mode when
3319 * PM usage counter is decremented.
3320 */
3321 pm_schedule_suspend(dev, 3000);
3322 return -EAGAIN;
3323 }
3324
Manu Gautamb5067272012-07-02 09:53:41 +05303325 return 0;
3326}
3327
3328static int dwc3_msm_runtime_suspend(struct device *dev)
3329{
3330 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3331
3332 dev_dbg(dev, "DWC3-msm runtime suspend\n");
3333
3334 return dwc3_msm_suspend(mdwc);
3335}
3336
3337static int dwc3_msm_runtime_resume(struct device *dev)
3338{
3339 struct dwc3_msm *mdwc = dev_get_drvdata(dev);
3340
3341 dev_dbg(dev, "DWC3-msm runtime resume\n");
3342
3343 return dwc3_msm_resume(mdwc);
3344}
3345
3346static const struct dev_pm_ops dwc3_msm_dev_pm_ops = {
3347 SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume)
3348 SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume,
3349 dwc3_msm_runtime_idle)
3350};
3351
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003352static const struct of_device_id of_dwc3_matach[] = {
3353 {
3354 .compatible = "qcom,dwc-usb3-msm",
3355 },
3356 { },
3357};
3358MODULE_DEVICE_TABLE(of, of_dwc3_matach);
3359
3360static struct platform_driver dwc3_msm_driver = {
3361 .probe = dwc3_msm_probe,
3362 .remove = __devexit_p(dwc3_msm_remove),
3363 .driver = {
3364 .name = "msm-dwc3",
Manu Gautamb5067272012-07-02 09:53:41 +05303365 .pm = &dwc3_msm_dev_pm_ops,
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003366 .of_match_table = of_dwc3_matach,
3367 },
3368};
3369
Manu Gautam377821c2012-09-28 16:53:24 +05303370MODULE_LICENSE("GPL v2");
Ido Shayevitzef72ddd2012-03-28 18:55:55 +02003371MODULE_DESCRIPTION("DesignWare USB3 MSM Glue Layer");
3372
3373static int __devinit dwc3_msm_init(void)
3374{
3375 return platform_driver_register(&dwc3_msm_driver);
3376}
3377module_init(dwc3_msm_init);
3378
3379static void __exit dwc3_msm_exit(void)
3380{
3381 platform_driver_unregister(&dwc3_msm_driver);
3382}
3383module_exit(dwc3_msm_exit);