Blame view

drivers/phy/phy-sun4i-usb.c 21.9 KB
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
1
2
3
  /*
   * Allwinner sun4i USB phy driver
   *
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
4
   * Copyright (C) 2014-2015 Hans de Goede <hdegoede@redhat.com>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   * Based on code from
   * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
   *
   * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
   * Copyright (C) 2013 Samsung Electronics Co., Ltd.
   * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   */
  
  #include <linux/clk.h>
1aedf3a7a   Hans de Goede   phy-sun4i-usb: Ad...
25
  #include <linux/delay.h>
2d84aff9c   Sachin Kamat   phy: sun4i-usb: U...
26
  #include <linux/err.h>
1a52abe68   Hans de Goede   phy-sun4i-usb: Ad...
27
  #include <linux/extcon.h>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
28
  #include <linux/io.h>
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
29
  #include <linux/interrupt.h>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
30
31
32
33
34
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/mutex.h>
  #include <linux/of.h>
  #include <linux/of_address.h>
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
35
  #include <linux/of_device.h>
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
36
  #include <linux/of_gpio.h>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
37
  #include <linux/phy/phy.h>
24fe86a61   Hans de Goede   phy: sun4i-usb: A...
38
  #include <linux/phy/phy-sun4i-usb.h>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
39
  #include <linux/platform_device.h>
8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
40
  #include <linux/power_supply.h>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
41
42
  #include <linux/regulator/consumer.h>
  #include <linux/reset.h>
919ab2524   Chen-Yu Tsai   phy: sun4i-usb: U...
43
  #include <linux/spinlock.h>
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
44
  #include <linux/usb/of.h>
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
45
  #include <linux/workqueue.h>
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
46
47
  
  #define REG_ISCR			0x00
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
48
  #define REG_PHYCTL_A10			0x04
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
49
50
  #define REG_PHYBIST			0x08
  #define REG_PHYTUNE			0x0c
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
51
  #define REG_PHYCTL_A33			0x10
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
52
  #define REG_PHY_UNK_H3			0x20
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
53
  #define REG_PMU_UNK1			0x10
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
54
55
56
57
58
59
60
  
  #define PHYCTL_DATA			BIT(7)
  
  #define SUNXI_AHB_ICHR8_EN		BIT(10)
  #define SUNXI_AHB_INCR4_BURST_EN	BIT(9)
  #define SUNXI_AHB_INCRX_ALIGN_EN	BIT(8)
  #define SUNXI_ULPI_BYPASS_EN		BIT(0)
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
61
62
63
64
65
66
67
68
69
70
  /* ISCR, Interface Status and Control bits */
  #define ISCR_ID_PULLUP_EN		(1 << 17)
  #define ISCR_DPDM_PULLUP_EN	(1 << 16)
  /* sunxi has the phy id/vbus pins not connected, so we use the force bits */
  #define ISCR_FORCE_ID_MASK	(3 << 14)
  #define ISCR_FORCE_ID_LOW		(2 << 14)
  #define ISCR_FORCE_ID_HIGH	(3 << 14)
  #define ISCR_FORCE_VBUS_MASK	(3 << 12)
  #define ISCR_FORCE_VBUS_LOW	(2 << 12)
  #define ISCR_FORCE_VBUS_HIGH	(3 << 12)
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
71
72
73
74
75
76
77
78
79
80
81
82
  /* Common Control Bits for Both PHYs */
  #define PHY_PLL_BW			0x03
  #define PHY_RES45_CAL_EN		0x0c
  
  /* Private Control Bits for Each PHY */
  #define PHY_TX_AMPLITUDE_TUNE		0x20
  #define PHY_TX_SLEWRATE_TUNE		0x22
  #define PHY_VBUSVALID_TH_SEL		0x25
  #define PHY_PULLUP_RES_SEL		0x27
  #define PHY_OTG_FUNC_EN			0x28
  #define PHY_VBUS_DET_EN			0x29
  #define PHY_DISCON_TH_SEL		0x2a
24fe86a61   Hans de Goede   phy: sun4i-usb: A...
83
  #define PHY_SQUELCH_DETECT		0x3c
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
84

626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
85
  #define MAX_PHYS			4
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
86

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
87
88
89
90
91
92
  /*
   * Note do not raise the debounce time, we must report Vusb high within 100ms
   * otherwise we get Vbus errors
   */
  #define DEBOUNCE_TIME			msecs_to_jiffies(50)
  #define POLL_TIME			msecs_to_jiffies(250)
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
93
94
  enum sun4i_usb_phy_type {
  	sun4i_a10_phy,
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
95
  	sun6i_a31_phy,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
96
  	sun8i_a33_phy,
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
97
  	sun8i_h3_phy,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
98
  	sun50i_a64_phy,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
99
100
101
102
103
104
105
106
  };
  
  struct sun4i_usb_phy_cfg {
  	int num_phys;
  	enum sun4i_usb_phy_type type;
  	u32 disc_thresh;
  	u8 phyctl_offset;
  	bool dedicated_clocks;
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
107
  	bool enable_pmu_unk1;
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
108
  };
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
109
  struct sun4i_usb_phy_data {
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
110
  	void __iomem *base;
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
111
  	const struct sun4i_usb_phy_cfg *cfg;
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
112
  	enum usb_dr_mode dr_mode;
919ab2524   Chen-Yu Tsai   phy: sun4i-usb: U...
113
  	spinlock_t reg_lock; /* guard access to phyctl reg */
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
114
115
116
117
118
  	struct sun4i_usb_phy {
  		struct phy *phy;
  		void __iomem *pmu;
  		struct regulator *vbus;
  		struct reset_control *reset;
eadd43123   Maxime Ripard   phy: usb: sunxi: ...
119
  		struct clk *clk;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
120
  		bool regulator_on;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
121
122
  		int index;
  	} phys[MAX_PHYS];
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
123
  	/* phy0 / otg related variables */
1a52abe68   Hans de Goede   phy-sun4i-usb: Ad...
124
  	struct extcon_dev *extcon;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
125
  	bool phy0_init;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
126
127
  	struct gpio_desc *id_det_gpio;
  	struct gpio_desc *vbus_det_gpio;
8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
128
129
130
  	struct power_supply *vbus_power_supply;
  	struct notifier_block vbus_power_nb;
  	bool vbus_power_nb_registered;
36f9159ba   Hans de Goede   phy-sun4i-usb: Re...
131
  	bool force_session_end;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
132
133
134
135
136
  	int id_det_irq;
  	int vbus_det_irq;
  	int id_det;
  	int vbus_det;
  	struct delayed_work detect;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
137
138
139
140
  };
  
  #define to_sun4i_usb_phy_data(phy) \
  	container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  static void sun4i_usb_phy0_update_iscr(struct phy *_phy, u32 clr, u32 set)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
  	u32 iscr;
  
  	iscr = readl(data->base + REG_ISCR);
  	iscr &= ~clr;
  	iscr |= set;
  	writel(iscr, data->base + REG_ISCR);
  }
  
  static void sun4i_usb_phy0_set_id_detect(struct phy *phy, u32 val)
  {
  	if (val)
  		val = ISCR_FORCE_ID_HIGH;
  	else
  		val = ISCR_FORCE_ID_LOW;
  
  	sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_ID_MASK, val);
  }
  
  static void sun4i_usb_phy0_set_vbus_detect(struct phy *phy, u32 val)
  {
  	if (val)
  		val = ISCR_FORCE_VBUS_HIGH;
  	else
  		val = ISCR_FORCE_VBUS_LOW;
  
  	sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_VBUS_MASK, val);
  }
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
172
173
174
175
176
  static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
  				int len)
  {
  	struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
  	u32 temp, usbc_bit = BIT(phy->index * 2);
d99cb3782   Ben Dooks   phy-sun4i-usb: fi...
177
  	void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset;
919ab2524   Chen-Yu Tsai   phy: sun4i-usb: U...
178
  	unsigned long flags;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
179
  	int i;
919ab2524   Chen-Yu Tsai   phy: sun4i-usb: U...
180
  	spin_lock_irqsave(&phy_data->reg_lock, flags);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
181

b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
182
183
184
  	if (phy_data->cfg->type == sun8i_a33_phy ||
  	    phy_data->cfg->type == sun50i_a64_phy) {
  		/* A33 or A64 needs us to set phyctl to 0 explicitly */
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
185
  		writel(0, phyctl);
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
186
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
187
  	for (i = 0; i < len; i++) {
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
188
  		temp = readl(phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
189
190
191
192
193
194
  
  		/* clear the address portion */
  		temp &= ~(0xff << 8);
  
  		/* set the address */
  		temp |= ((addr + i) << 8);
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
195
  		writel(temp, phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
196
197
  
  		/* set the data bit and clear usbc bit*/
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
198
  		temp = readb(phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
199
200
201
202
203
  		if (data & 0x1)
  			temp |= PHYCTL_DATA;
  		else
  			temp &= ~PHYCTL_DATA;
  		temp &= ~usbc_bit;
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
204
  		writeb(temp, phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
205
206
  
  		/* pulse usbc_bit */
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
207
  		temp = readb(phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
208
  		temp |= usbc_bit;
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
209
  		writeb(temp, phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
210

fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
211
  		temp = readb(phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
212
  		temp &= ~usbc_bit;
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
213
  		writeb(temp, phyctl);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
214
215
216
  
  		data >>= 1;
  	}
919ab2524   Chen-Yu Tsai   phy: sun4i-usb: U...
217
218
  
  	spin_unlock_irqrestore(&phy_data->reg_lock, flags);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  }
  
  static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
  {
  	u32 bits, reg_value;
  
  	if (!phy->pmu)
  		return;
  
  	bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
  		SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
  
  	reg_value = readl(phy->pmu);
  
  	if (enable)
  		reg_value |= bits;
  	else
  		reg_value &= ~bits;
  
  	writel(reg_value, phy->pmu);
  }
  
  static int sun4i_usb_phy_init(struct phy *_phy)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
  	int ret;
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
246
  	u32 val;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
247

eadd43123   Maxime Ripard   phy: usb: sunxi: ...
248
  	ret = clk_prepare_enable(phy->clk);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
249
250
251
252
253
  	if (ret)
  		return ret;
  
  	ret = reset_control_deassert(phy->reset);
  	if (ret) {
eadd43123   Maxime Ripard   phy: usb: sunxi: ...
254
  		clk_disable_unprepare(phy->clk);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
255
256
  		return ret;
  	}
4320f9d4c   Icenowy Zheng   phy: sun4i: check...
257
  	if (phy->pmu && data->cfg->enable_pmu_unk1) {
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
258
259
260
  		val = readl(phy->pmu + REG_PMU_UNK1);
  		writel(val & ~2, phy->pmu + REG_PMU_UNK1);
  	}
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
261
262
263
264
265
  	if (data->cfg->type == sun8i_h3_phy) {
  		if (phy->index == 0) {
  			val = readl(data->base + REG_PHY_UNK_H3);
  			writel(val & ~1, data->base + REG_PHY_UNK_H3);
  		}
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
266
267
268
269
  	} else {
  		/* Enable USB 45 Ohm resistor calibration */
  		if (phy->index == 0)
  			sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
6827a46f5   Roman Byshko   phy: sun4i: add s...
270

626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
271
272
  		/* Adjust PHY's magnitude and rate */
  		sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
273

626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
274
275
276
277
  		/* Disconnect threshold adjustment */
  		sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
  				    data->cfg->disc_thresh, 2);
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
278
279
  
  	sun4i_usb_phy_passby(phy, 1);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
280
281
282
283
284
285
  	if (phy->index == 0) {
  		data->phy0_init = true;
  
  		/* Enable pull-ups */
  		sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_DPDM_PULLUP_EN);
  		sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_ID_PULLUP_EN);
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
286
287
288
289
  		/* Force ISCR and cable state updates */
  		data->id_det = -1;
  		data->vbus_det = -1;
  		queue_delayed_work(system_wq, &data->detect, 0);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
290
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
291
292
293
294
295
296
  	return 0;
  }
  
  static int sun4i_usb_phy_exit(struct phy *_phy)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
297
298
299
300
301
302
303
304
  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
  
  	if (phy->index == 0) {
  		/* Disable pull-ups */
  		sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0);
  		sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0);
  		data->phy0_init = false;
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
305
306
307
  
  	sun4i_usb_phy_passby(phy, 0);
  	reset_control_assert(phy->reset);
eadd43123   Maxime Ripard   phy: usb: sunxi: ...
308
  	clk_disable_unprepare(phy->clk);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
309
310
311
  
  	return 0;
  }
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
312
313
314
315
  static int sun4i_usb_phy0_get_id_det(struct sun4i_usb_phy_data *data)
  {
  	switch (data->dr_mode) {
  	case USB_DR_MODE_OTG:
5f90d31ca   Hans de Goede   phy-sun4i-usb: Si...
316
317
318
319
  		if (data->id_det_gpio)
  			return gpiod_get_value_cansleep(data->id_det_gpio);
  		else
  			return 1; /* Fallback to peripheral mode */
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
320
321
322
323
324
325
326
  	case USB_DR_MODE_HOST:
  		return 0;
  	case USB_DR_MODE_PERIPHERAL:
  	default:
  		return 1;
  	}
  }
3d772c4ad   Hans de Goede   phy-sun4i-sub: Mo...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data)
  {
  	if (data->vbus_det_gpio)
  		return gpiod_get_value_cansleep(data->vbus_det_gpio);
  
  	if (data->vbus_power_supply) {
  		union power_supply_propval val;
  		int r;
  
  		r = power_supply_get_property(data->vbus_power_supply,
  					      POWER_SUPPLY_PROP_PRESENT, &val);
  		if (r == 0)
  			return val.intval;
  	}
  
  	/* Fallback: report vbus as high */
  	return 1;
  }
  
  static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data)
  {
  	return data->vbus_det_gpio || data->vbus_power_supply;
  }
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
  {
  	if ((data->id_det_gpio && data->id_det_irq <= 0) ||
  	    (data->vbus_det_gpio && data->vbus_det_irq <= 0))
  		return true;
  
  	/*
  	 * The A31 companion pmic (axp221) does not generate vbus change
  	 * interrupts when the board is driving vbus, so we must poll
  	 * when using the pmic for vbus-det _and_ we're driving vbus.
  	 */
  	if (data->cfg->type == sun6i_a31_phy &&
  	    data->vbus_power_supply && data->phys[0].regulator_on)
  		return true;
  
  	return false;
  }
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
367
368
369
  static int sun4i_usb_phy_power_on(struct phy *_phy)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
370
371
372
373
374
375
376
  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
  	int ret;
  
  	if (!phy->vbus || phy->regulator_on)
  		return 0;
  
  	/* For phy0 only turn on Vbus if we don't have an ext. Vbus */
8083526e0   Hans de Goede   phy-sun4i-usb: On...
377
  	if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) &&
91d6e3b6b   Hans de Goede   phy-sun4i-usb: Wa...
378
379
380
  				data->vbus_det) {
  		dev_warn(&_phy->dev, "External vbus detected, not enabling our own vbus
  ");
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
381
  		return 0;
91d6e3b6b   Hans de Goede   phy-sun4i-usb: Wa...
382
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
383

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
384
385
386
  	ret = regulator_enable(phy->vbus);
  	if (ret)
  		return ret;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
387

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
388
  	phy->regulator_on = true;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
389

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
390
  	/* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
391
  	if (phy->index == 0 && sun4i_usb_phy0_poll(data))
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
392
  		mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
393

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
394
  	return 0;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
395
396
397
398
399
  }
  
  static int sun4i_usb_phy_power_off(struct phy *_phy)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
400
401
402
403
  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
  
  	if (!phy->vbus || !phy->regulator_on)
  		return 0;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
404

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
405
406
  	regulator_disable(phy->vbus);
  	phy->regulator_on = false;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
407

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
408
409
410
411
  	/*
  	 * phy0 vbus typically slowly discharges, sometimes this causes the
  	 * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan.
  	 */
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
412
  	if (phy->index == 0 && !sun4i_usb_phy0_poll(data))
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
413
  		mod_delayed_work(system_wq, &data->detect, POLL_TIME);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
414
415
416
  
  	return 0;
  }
6ba43c291   Hans de Goede   phy-sun4i-usb: Ad...
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  static int sun4i_usb_phy_set_mode(struct phy *_phy, enum phy_mode mode)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
  
  	if (phy->index != 0)
  		return -EINVAL;
  
  	switch (mode) {
  	case PHY_MODE_USB_HOST:
  		data->dr_mode = USB_DR_MODE_HOST;
  		break;
  	case PHY_MODE_USB_DEVICE:
  		data->dr_mode = USB_DR_MODE_PERIPHERAL;
  		break;
  	case PHY_MODE_USB_OTG:
  		data->dr_mode = USB_DR_MODE_OTG;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	dev_info(&_phy->dev, "Changing dr_mode to %d
  ", (int)data->dr_mode);
  	data->force_session_end = true;
  	queue_delayed_work(system_wq, &data->detect, 0);
  
  	return 0;
  }
24fe86a61   Hans de Goede   phy: sun4i-usb: A...
446
447
448
449
450
451
  void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
  {
  	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
  
  	sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
  }
7167bf8b7   Hans de Goede   phy-sun4i-usb: Ad...
452
  EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
24fe86a61   Hans de Goede   phy: sun4i-usb: A...
453

4a9e5ca1a   Axel Lin   phy: Constify str...
454
  static const struct phy_ops sun4i_usb_phy_ops = {
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
455
456
457
458
  	.init		= sun4i_usb_phy_init,
  	.exit		= sun4i_usb_phy_exit,
  	.power_on	= sun4i_usb_phy_power_on,
  	.power_off	= sun4i_usb_phy_power_off,
6ba43c291   Hans de Goede   phy-sun4i-usb: Ad...
459
  	.set_mode	= sun4i_usb_phy_set_mode,
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
460
461
  	.owner		= THIS_MODULE,
  };
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
462
463
464
465
466
  static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
  {
  	struct sun4i_usb_phy_data *data =
  		container_of(work, struct sun4i_usb_phy_data, detect.work);
  	struct phy *phy0 = data->phys[0].phy;
36f9159ba   Hans de Goede   phy-sun4i-usb: Re...
467
  	bool force_session_end, id_notify = false, vbus_notify = false;
9745ceebc   Hans de Goede   phy-sun4i-usb: Us...
468
  	int id_det, vbus_det;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
469

b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
470
471
472
473
  	if (phy0 == NULL)
  		return;
  
  	id_det = sun4i_usb_phy0_get_id_det(data);
8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
474
  	vbus_det = sun4i_usb_phy0_get_vbus_det(data);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
475
476
477
478
479
480
481
  
  	mutex_lock(&phy0->mutex);
  
  	if (!data->phy0_init) {
  		mutex_unlock(&phy0->mutex);
  		return;
  	}
36f9159ba   Hans de Goede   phy-sun4i-usb: Re...
482
483
  	force_session_end = data->force_session_end;
  	data->force_session_end = false;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
484
  	if (id_det != data->id_det) {
36f9159ba   Hans de Goede   phy-sun4i-usb: Re...
485
  		/* id-change, force session end if we've no vbus detection */
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
486
  		if (data->dr_mode == USB_DR_MODE_OTG &&
36f9159ba   Hans de Goede   phy-sun4i-usb: Re...
487
488
489
490
491
  		    !sun4i_usb_phy0_have_vbus_det(data))
  			force_session_end = true;
  
  		/* When entering host mode (id = 0) force end the session now */
  		if (force_session_end && id_det == 0) {
1aedf3a7a   Hans de Goede   phy-sun4i-usb: Ad...
492
493
494
495
  			sun4i_usb_phy0_set_vbus_detect(phy0, 0);
  			msleep(200);
  			sun4i_usb_phy0_set_vbus_detect(phy0, 1);
  		}
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
496
497
  		sun4i_usb_phy0_set_id_detect(phy0, id_det);
  		data->id_det = id_det;
9745ceebc   Hans de Goede   phy-sun4i-usb: Us...
498
  		id_notify = true;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
499
500
501
502
503
  	}
  
  	if (vbus_det != data->vbus_det) {
  		sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det);
  		data->vbus_det = vbus_det;
9745ceebc   Hans de Goede   phy-sun4i-usb: Us...
504
  		vbus_notify = true;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
505
506
507
  	}
  
  	mutex_unlock(&phy0->mutex);
1aedf3a7a   Hans de Goede   phy-sun4i-usb: Ad...
508
  	if (id_notify) {
1a52abe68   Hans de Goede   phy-sun4i-usb: Ad...
509
510
  		extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST,
  					!id_det);
36f9159ba   Hans de Goede   phy-sun4i-usb: Re...
511
512
  		/* When leaving host mode force end the session here */
  		if (force_session_end && id_det == 1) {
1aedf3a7a   Hans de Goede   phy-sun4i-usb: Ad...
513
514
515
516
517
518
519
  			mutex_lock(&phy0->mutex);
  			sun4i_usb_phy0_set_vbus_detect(phy0, 0);
  			msleep(1000);
  			sun4i_usb_phy0_set_vbus_detect(phy0, 1);
  			mutex_unlock(&phy0->mutex);
  		}
  	}
1a52abe68   Hans de Goede   phy-sun4i-usb: Ad...
520
521
522
  
  	if (vbus_notify)
  		extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
523
  	if (sun4i_usb_phy0_poll(data))
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
524
525
526
527
528
529
530
531
532
533
534
535
  		queue_delayed_work(system_wq, &data->detect, POLL_TIME);
  }
  
  static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id)
  {
  	struct sun4i_usb_phy_data *data = dev_id;
  
  	/* vbus or id changed, let the pins settle and then scan them */
  	mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
  
  	return IRQ_HANDLED;
  }
8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
536
537
538
539
540
541
542
543
544
545
546
547
548
  static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb,
  				      unsigned long val, void *v)
  {
  	struct sun4i_usb_phy_data *data =
  		container_of(nb, struct sun4i_usb_phy_data, vbus_power_nb);
  	struct power_supply *psy = v;
  
  	/* Properties on the vbus_power_supply changed, scan vbus_det */
  	if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply)
  		mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
  
  	return NOTIFY_OK;
  }
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
549
550
551
552
  static struct phy *sun4i_usb_phy_xlate(struct device *dev,
  					struct of_phandle_args *args)
  {
  	struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
5f90d31ca   Hans de Goede   phy-sun4i-usb: Si...
553
  	if (args->args[0] >= data->cfg->num_phys)
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
554
555
556
557
  		return ERR_PTR(-ENODEV);
  
  	return data->phys[args->args[0]].phy;
  }
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
558
559
560
561
  static int sun4i_usb_phy_remove(struct platform_device *pdev)
  {
  	struct device *dev = &pdev->dev;
  	struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
562
563
  	if (data->vbus_power_nb_registered)
  		power_supply_unreg_notifier(&data->vbus_power_nb);
04e59a021   Hans de Goede   phy-sun4i-usb: Fi...
564
  	if (data->id_det_irq > 0)
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
565
  		devm_free_irq(dev, data->id_det_irq, data);
04e59a021   Hans de Goede   phy-sun4i-usb: Fi...
566
  	if (data->vbus_det_irq > 0)
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
567
568
569
570
571
572
  		devm_free_irq(dev, data->vbus_det_irq, data);
  
  	cancel_delayed_work_sync(&data->detect);
  
  	return 0;
  }
1a52abe68   Hans de Goede   phy-sun4i-usb: Ad...
573
574
575
576
577
  static const unsigned int sun4i_usb_phy0_cable[] = {
  	EXTCON_USB,
  	EXTCON_USB_HOST,
  	EXTCON_NONE,
  };
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
578
579
580
581
582
  static int sun4i_usb_phy_probe(struct platform_device *pdev)
  {
  	struct sun4i_usb_phy_data *data;
  	struct device *dev = &pdev->dev;
  	struct device_node *np = dev->of_node;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
583
  	struct phy_provider *phy_provider;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
584
  	struct resource *res;
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
585
  	int i, ret;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
586
587
588
589
  
  	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
919ab2524   Chen-Yu Tsai   phy: sun4i-usb: U...
590
  	spin_lock_init(&data->reg_lock);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
591
592
  	INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan);
  	dev_set_drvdata(dev, data);
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
593
594
595
  	data->cfg = of_device_get_match_data(dev);
  	if (!data->cfg)
  		return -EINVAL;
fc1f45ed3   Hans de Goede   phy-sun4i-usb: Ad...
596

ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
597
598
599
600
  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
  	data->base = devm_ioremap_resource(dev, res);
  	if (IS_ERR(data->base))
  		return PTR_ERR(data->base);
b2dfc34c9   Axel Lin   phy: sun4i-usb: U...
601
602
603
604
605
606
607
608
609
  	data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det",
  						    GPIOD_IN);
  	if (IS_ERR(data->id_det_gpio))
  		return PTR_ERR(data->id_det_gpio);
  
  	data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det",
  						      GPIOD_IN);
  	if (IS_ERR(data->vbus_det_gpio))
  		return PTR_ERR(data->vbus_det_gpio);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
610

8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
611
612
613
614
615
616
617
618
619
  	if (of_find_property(np, "usb0_vbus_power-supply", NULL)) {
  		data->vbus_power_supply = devm_power_supply_get_by_phandle(dev,
  						     "usb0_vbus_power-supply");
  		if (IS_ERR(data->vbus_power_supply))
  			return PTR_ERR(data->vbus_power_supply);
  
  		if (!data->vbus_power_supply)
  			return -EPROBE_DEFER;
  	}
b33ecca87   Hans de Goede   phy-sun4i-usb: Ad...
620
  	data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0);
5f90d31ca   Hans de Goede   phy-sun4i-usb: Si...
621
622
623
624
625
626
627
628
629
630
  
  	data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable);
  	if (IS_ERR(data->extcon))
  		return PTR_ERR(data->extcon);
  
  	ret = devm_extcon_dev_register(dev, data->extcon);
  	if (ret) {
  		dev_err(dev, "failed to register extcon: %d
  ", ret);
  		return ret;
1a52abe68   Hans de Goede   phy-sun4i-usb: Ad...
631
  	}
5f90d31ca   Hans de Goede   phy-sun4i-usb: Si...
632
  	for (i = 0; i < data->cfg->num_phys; i++) {
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
633
634
  		struct sun4i_usb_phy *phy = data->phys + i;
  		char name[16];
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
635
  		snprintf(name, sizeof(name), "usb%d_vbus", i);
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
636
637
638
  		phy->vbus = devm_regulator_get_optional(dev, name);
  		if (IS_ERR(phy->vbus)) {
  			if (PTR_ERR(phy->vbus) == -EPROBE_DEFER)
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
639
  				return -EPROBE_DEFER;
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
640
  			phy->vbus = NULL;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
641
  		}
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
642
  		if (data->cfg->dedicated_clocks)
eadd43123   Maxime Ripard   phy: usb: sunxi: ...
643
644
645
646
647
648
649
650
651
652
  			snprintf(name, sizeof(name), "usb%d_phy", i);
  		else
  			strlcpy(name, "usb_phy", sizeof(name));
  
  		phy->clk = devm_clk_get(dev, name);
  		if (IS_ERR(phy->clk)) {
  			dev_err(dev, "failed to get clock %s
  ", name);
  			return PTR_ERR(phy->clk);
  		}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
653
  		snprintf(name, sizeof(name), "usb%d_reset", i);
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
654
655
  		phy->reset = devm_reset_control_get(dev, name);
  		if (IS_ERR(phy->reset)) {
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
656
657
  			dev_err(dev, "failed to get reset %s
  ", name);
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
658
  			return PTR_ERR(phy->reset);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
659
660
661
662
663
664
  		}
  
  		if (i) { /* No pmu for usbc0 */
  			snprintf(name, sizeof(name), "pmu%d", i);
  			res = platform_get_resource_byname(pdev,
  							IORESOURCE_MEM, name);
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
665
666
667
  			phy->pmu = devm_ioremap_resource(dev, res);
  			if (IS_ERR(phy->pmu))
  				return PTR_ERR(phy->pmu);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
668
  		}
dbc98635e   Heikki Krogerus   phy: remove the o...
669
  		phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops);
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
670
  		if (IS_ERR(phy->phy)) {
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
671
672
  			dev_err(dev, "failed to create PHY %d
  ", i);
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
673
  			return PTR_ERR(phy->phy);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
674
  		}
2a7f9982d   Maxime Ripard   phy: sunxi: Rewor...
675
676
  		phy->index = i;
  		phy_set_drvdata(phy->phy, &data->phys[i]);
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
677
  	}
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
678
  	data->id_det_irq = gpiod_to_irq(data->id_det_gpio);
5cf700ac9   Quentin Schulz   phy: phy-sun4i-us...
679
  	if (data->id_det_irq > 0) {
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
680
681
682
683
684
685
686
687
688
689
  		ret = devm_request_irq(dev, data->id_det_irq,
  				sun4i_usb_phy0_id_vbus_det_irq,
  				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
  				"usb0-id-det", data);
  		if (ret) {
  			dev_err(dev, "Err requesting id-det-irq: %d
  ", ret);
  			return ret;
  		}
  	}
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
690
  	data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
5cf700ac9   Quentin Schulz   phy: phy-sun4i-us...
691
  	if (data->vbus_det_irq > 0) {
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
692
693
694
695
696
697
698
699
700
701
702
703
  		ret = devm_request_irq(dev, data->vbus_det_irq,
  				sun4i_usb_phy0_id_vbus_det_irq,
  				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
  				"usb0-vbus-det", data);
  		if (ret) {
  			dev_err(dev, "Err requesting vbus-det-irq: %d
  ", ret);
  			data->vbus_det_irq = -1;
  			sun4i_usb_phy_remove(pdev); /* Stop detect work */
  			return ret;
  		}
  	}
8665c18be   Hans de Goede   phy-sun4i-usb: Ad...
704
705
706
707
708
709
710
711
712
713
  	if (data->vbus_power_supply) {
  		data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify;
  		data->vbus_power_nb.priority = 0;
  		ret = power_supply_reg_notifier(&data->vbus_power_nb);
  		if (ret) {
  			sun4i_usb_phy_remove(pdev); /* Stop detect work */
  			return ret;
  		}
  		data->vbus_power_nb_registered = true;
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
714
  	phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
715
716
717
718
  	if (IS_ERR(phy_provider)) {
  		sun4i_usb_phy_remove(pdev); /* Stop detect work */
  		return PTR_ERR(phy_provider);
  	}
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
719

d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
720
  	return 0;
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
721
  }
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
722
723
724
725
726
727
  static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
  	.num_phys = 3,
  	.type = sun4i_a10_phy,
  	.disc_thresh = 3,
  	.phyctl_offset = REG_PHYCTL_A10,
  	.dedicated_clocks = false,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
728
  	.enable_pmu_unk1 = false,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
729
730
731
732
733
734
735
736
  };
  
  static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
  	.num_phys = 2,
  	.type = sun4i_a10_phy,
  	.disc_thresh = 2,
  	.phyctl_offset = REG_PHYCTL_A10,
  	.dedicated_clocks = false,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
737
  	.enable_pmu_unk1 = false,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
738
739
740
741
  };
  
  static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
  	.num_phys = 3,
91d96f06a   Hans de Goede   phy-sun4i-usb: Ad...
742
  	.type = sun6i_a31_phy,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
743
744
745
  	.disc_thresh = 3,
  	.phyctl_offset = REG_PHYCTL_A10,
  	.dedicated_clocks = true,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
746
  	.enable_pmu_unk1 = false,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
747
748
749
750
751
752
753
754
  };
  
  static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
  	.num_phys = 3,
  	.type = sun4i_a10_phy,
  	.disc_thresh = 2,
  	.phyctl_offset = REG_PHYCTL_A10,
  	.dedicated_clocks = false,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
755
  	.enable_pmu_unk1 = false,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
756
757
758
759
760
761
762
763
  };
  
  static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
  	.num_phys = 2,
  	.type = sun4i_a10_phy,
  	.disc_thresh = 3,
  	.phyctl_offset = REG_PHYCTL_A10,
  	.dedicated_clocks = true,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
764
  	.enable_pmu_unk1 = false,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
765
766
767
768
769
770
771
772
  };
  
  static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
  	.num_phys = 2,
  	.type = sun8i_a33_phy,
  	.disc_thresh = 3,
  	.phyctl_offset = REG_PHYCTL_A33,
  	.dedicated_clocks = true,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
773
  	.enable_pmu_unk1 = false,
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
774
  };
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
775
776
777
778
779
  static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
  	.num_phys = 4,
  	.type = sun8i_h3_phy,
  	.disc_thresh = 3,
  	.dedicated_clocks = true,
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
780
781
782
783
784
785
786
787
788
789
  	.enable_pmu_unk1 = true,
  };
  
  static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
  	.num_phys = 2,
  	.type = sun50i_a64_phy,
  	.disc_thresh = 3,
  	.phyctl_offset = REG_PHYCTL_A33,
  	.dedicated_clocks = true,
  	.enable_pmu_unk1 = true,
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
790
  };
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
791
  static const struct of_device_id sun4i_usb_phy_of_match[] = {
68dbc2ce7   Hans de Goede   phy-sun4i-usb: Us...
792
793
794
795
796
797
  	{ .compatible = "allwinner,sun4i-a10-usb-phy", .data = &sun4i_a10_cfg },
  	{ .compatible = "allwinner,sun5i-a13-usb-phy", .data = &sun5i_a13_cfg },
  	{ .compatible = "allwinner,sun6i-a31-usb-phy", .data = &sun6i_a31_cfg },
  	{ .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },
  	{ .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
  	{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
626a630e0   Reinder de Haan   phy-sun4i-usb: Ad...
798
  	{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
b3e0d141c   Icenowy Zheng   phy: sun4i: add s...
799
800
  	{ .compatible = "allwinner,sun50i-a64-usb-phy",
  	  .data = &sun50i_a64_cfg},
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
801
802
803
804
805
806
  	{ },
  };
  MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
  
  static struct platform_driver sun4i_usb_phy_driver = {
  	.probe	= sun4i_usb_phy_probe,
d2332303e   Hans de Goede   phy-sun4i-usb: Ad...
807
  	.remove	= sun4i_usb_phy_remove,
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
808
809
810
  	.driver = {
  		.of_match_table	= sun4i_usb_phy_of_match,
  		.name  = "sun4i-usb-phy",
ba4bdc9e1   Hans de Goede   PHY: sunxi: Add d...
811
812
813
814
815
816
817
  	}
  };
  module_platform_driver(sun4i_usb_phy_driver);
  
  MODULE_DESCRIPTION("Allwinner sun4i USB phy driver");
  MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
  MODULE_LICENSE("GPL v2");