Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2/**
3 * tusb1210.c - TUSB1210 USB ULPI PHY driver
4 *
5 * Copyright (C) 2015 Intel Corporation
6 *
7 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
8 */
9#include <linux/module.h>
10#include <linux/ulpi/driver.h>
11#include <linux/ulpi/regs.h>
12#include <linux/gpio/consumer.h>
13#include <linux/phy/ulpi_phy.h>
14
15#define TUSB1210_VENDOR_SPECIFIC2 0x80
16#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0
17#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4
18#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6
19
20struct tusb1210 {
21 struct ulpi *ulpi;
22 struct phy *phy;
23 struct gpio_desc *gpio_reset;
24 struct gpio_desc *gpio_cs;
25 u8 vendor_specific2;
26};
27
28static int tusb1210_power_on(struct phy *phy)
29{
30 struct tusb1210 *tusb = phy_get_drvdata(phy);
31
32 gpiod_set_value_cansleep(tusb->gpio_reset, 1);
33 gpiod_set_value_cansleep(tusb->gpio_cs, 1);
34
35 /* Restore the optional eye diagram optimization value */
36 if (tusb->vendor_specific2)
37 ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
38 tusb->vendor_specific2);
39
40 return 0;
41}
42
43static int tusb1210_power_off(struct phy *phy)
44{
45 struct tusb1210 *tusb = phy_get_drvdata(phy);
46
47 gpiod_set_value_cansleep(tusb->gpio_reset, 0);
48 gpiod_set_value_cansleep(tusb->gpio_cs, 0);
49
50 return 0;
51}
52
53static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
54{
55 struct tusb1210 *tusb = phy_get_drvdata(phy);
56 int ret;
57
58 ret = ulpi_read(tusb->ulpi, ULPI_OTG_CTRL);
59 if (ret < 0)
60 return ret;
61
62 switch (mode) {
63 case PHY_MODE_USB_HOST:
64 ret |= (ULPI_OTG_CTRL_DRVVBUS_EXT
65 | ULPI_OTG_CTRL_ID_PULLUP
66 | ULPI_OTG_CTRL_DP_PULLDOWN
67 | ULPI_OTG_CTRL_DM_PULLDOWN);
68 ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
69 ret |= ULPI_OTG_CTRL_DRVVBUS;
70 break;
71 case PHY_MODE_USB_DEVICE:
72 ret &= ~(ULPI_OTG_CTRL_DRVVBUS
73 | ULPI_OTG_CTRL_DP_PULLDOWN
74 | ULPI_OTG_CTRL_DM_PULLDOWN);
75 ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
76 ret &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
77 break;
78 default:
79 /* nothing */
80 return 0;
81 }
82
83 return ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
84}
85
86static const struct phy_ops phy_ops = {
87 .power_on = tusb1210_power_on,
88 .power_off = tusb1210_power_off,
89 .set_mode = tusb1210_set_mode,
90 .owner = THIS_MODULE,
91};
92
93static int tusb1210_probe(struct ulpi *ulpi)
94{
95 struct tusb1210 *tusb;
96 u8 val, reg;
97
98 tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
99 if (!tusb)
100 return -ENOMEM;
101
102 tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
103 GPIOD_OUT_LOW);
104 if (IS_ERR(tusb->gpio_reset))
105 return PTR_ERR(tusb->gpio_reset);
106
107 gpiod_set_value_cansleep(tusb->gpio_reset, 1);
108
109 tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs",
110 GPIOD_OUT_LOW);
111 if (IS_ERR(tusb->gpio_cs))
112 return PTR_ERR(tusb->gpio_cs);
113
114 gpiod_set_value_cansleep(tusb->gpio_cs, 1);
115
116 /*
117 * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
118 * diagram optimization and DP/DM swap.
119 */
120
121 /* High speed output drive strength configuration */
122 device_property_read_u8(&ulpi->dev, "ihstx", &val);
123 reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT;
124
125 /* High speed output impedance configuration */
126 device_property_read_u8(&ulpi->dev, "zhsdrv", &val);
127 reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT;
128
129 /* DP/DM swap control */
130 device_property_read_u8(&ulpi->dev, "datapolarity", &val);
131 reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT;
132
133 if (reg) {
134 ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
135 tusb->vendor_specific2 = reg;
136 }
137
138 tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
139 if (IS_ERR(tusb->phy))
140 return PTR_ERR(tusb->phy);
141
142 tusb->ulpi = ulpi;
143
144 phy_set_drvdata(tusb->phy, tusb);
145 ulpi_set_drvdata(ulpi, tusb);
146 return 0;
147}
148
149static void tusb1210_remove(struct ulpi *ulpi)
150{
151 struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
152
153 ulpi_phy_destroy(ulpi, tusb->phy);
154}
155
156#define TI_VENDOR_ID 0x0451
157
158static const struct ulpi_device_id tusb1210_ulpi_id[] = {
159 { TI_VENDOR_ID, 0x1507, }, /* TUSB1210 */
160 { TI_VENDOR_ID, 0x1508, }, /* TUSB1211 */
161 { },
162};
163MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
164
165static struct ulpi_driver tusb1210_driver = {
166 .id_table = tusb1210_ulpi_id,
167 .probe = tusb1210_probe,
168 .remove = tusb1210_remove,
169 .driver = {
170 .name = "tusb1210",
171 .owner = THIS_MODULE,
172 },
173};
174
175module_ulpi_driver(tusb1210_driver);
176
177MODULE_AUTHOR("Intel Corporation");
178MODULE_LICENSE("GPL v2");
179MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * tusb1210.c - TUSB1210 USB ULPI PHY driver
4 *
5 * Copyright (C) 2015 Intel Corporation
6 *
7 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
8 */
9#include <linux/module.h>
10#include <linux/bitfield.h>
11#include <linux/delay.h>
12#include <linux/ulpi/driver.h>
13#include <linux/ulpi/regs.h>
14#include <linux/gpio/consumer.h>
15#include <linux/phy/ulpi_phy.h>
16#include <linux/power_supply.h>
17#include <linux/property.h>
18#include <linux/workqueue.h>
19
20#define TI_VENDOR_ID 0x0451
21#define TI_DEVICE_TUSB1210 0x1507
22#define TI_DEVICE_TUSB1211 0x1508
23
24#define TUSB1211_POWER_CONTROL 0x3d
25#define TUSB1211_POWER_CONTROL_SET 0x3e
26#define TUSB1211_POWER_CONTROL_CLEAR 0x3f
27#define TUSB1211_POWER_CONTROL_SW_CONTROL BIT(0)
28#define TUSB1211_POWER_CONTROL_DET_COMP BIT(1)
29#define TUSB1211_POWER_CONTROL_DP_VSRC_EN BIT(6)
30
31#define TUSB1210_VENDOR_SPECIFIC2 0x80
32#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK GENMASK(3, 0)
33#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK GENMASK(5, 4)
34#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK BIT(6)
35
36#define TUSB1211_VENDOR_SPECIFIC3 0x85
37#define TUSB1211_VENDOR_SPECIFIC3_SET 0x86
38#define TUSB1211_VENDOR_SPECIFIC3_CLEAR 0x87
39#define TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET BIT(4)
40#define TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN BIT(6)
41
42#define TUSB1210_RESET_TIME_MS 50
43
44#define TUSB1210_CHG_DET_MAX_RETRIES 5
45
46/* TUSB1210 charger detection work states */
47enum tusb1210_chg_det_state {
48 TUSB1210_CHG_DET_CONNECTING,
49 TUSB1210_CHG_DET_START_DET,
50 TUSB1210_CHG_DET_READ_DET,
51 TUSB1210_CHG_DET_FINISH_DET,
52 TUSB1210_CHG_DET_CONNECTED,
53 TUSB1210_CHG_DET_DISCONNECTING,
54 TUSB1210_CHG_DET_DISCONNECTING_DONE,
55 TUSB1210_CHG_DET_DISCONNECTED,
56};
57
58struct tusb1210 {
59 struct device *dev;
60 struct phy *phy;
61 struct gpio_desc *gpio_reset;
62 struct gpio_desc *gpio_cs;
63 u8 otg_ctrl;
64 u8 vendor_specific2;
65#ifdef CONFIG_POWER_SUPPLY
66 enum power_supply_usb_type chg_type;
67 enum tusb1210_chg_det_state chg_det_state;
68 int chg_det_retries;
69 struct delayed_work chg_det_work;
70 struct notifier_block psy_nb;
71 struct power_supply *psy;
72#endif
73};
74
75static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
76{
77 struct device *dev = tusb->dev;
78 int ret;
79
80 ret = ulpi_write(to_ulpi_dev(dev), reg, val);
81 if (ret)
82 dev_err(dev, "error %d writing val 0x%02x to reg 0x%02x\n", ret, val, reg);
83
84 return ret;
85}
86
87static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val)
88{
89 struct device *dev = tusb->dev;
90 int ret;
91
92 ret = ulpi_read(to_ulpi_dev(dev), reg);
93 if (ret >= 0) {
94 *val = ret;
95 ret = 0;
96 } else {
97 dev_err(dev, "error %d reading reg 0x%02x\n", ret, reg);
98 }
99
100 return ret;
101}
102
103static int tusb1210_power_on(struct phy *phy)
104{
105 struct tusb1210 *tusb = phy_get_drvdata(phy);
106
107 gpiod_set_value_cansleep(tusb->gpio_reset, 1);
108 gpiod_set_value_cansleep(tusb->gpio_cs, 1);
109
110 msleep(TUSB1210_RESET_TIME_MS);
111
112 /* Restore the optional eye diagram optimization value */
113 tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, tusb->vendor_specific2);
114
115 return 0;
116}
117
118static int tusb1210_power_off(struct phy *phy)
119{
120 struct tusb1210 *tusb = phy_get_drvdata(phy);
121
122 gpiod_set_value_cansleep(tusb->gpio_reset, 0);
123 gpiod_set_value_cansleep(tusb->gpio_cs, 0);
124
125 return 0;
126}
127
128static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
129{
130 struct tusb1210 *tusb = phy_get_drvdata(phy);
131 int ret;
132 u8 reg;
133
134 ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, ®);
135 if (ret < 0)
136 return ret;
137
138 switch (mode) {
139 case PHY_MODE_USB_HOST:
140 reg |= (ULPI_OTG_CTRL_DRVVBUS_EXT
141 | ULPI_OTG_CTRL_ID_PULLUP
142 | ULPI_OTG_CTRL_DP_PULLDOWN
143 | ULPI_OTG_CTRL_DM_PULLDOWN);
144 tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
145 reg |= ULPI_OTG_CTRL_DRVVBUS;
146 break;
147 case PHY_MODE_USB_DEVICE:
148 reg &= ~(ULPI_OTG_CTRL_DRVVBUS
149 | ULPI_OTG_CTRL_DP_PULLDOWN
150 | ULPI_OTG_CTRL_DM_PULLDOWN);
151 tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
152 reg &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
153 break;
154 default:
155 /* nothing */
156 return 0;
157 }
158
159 tusb->otg_ctrl = reg;
160 return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
161}
162
163#ifdef CONFIG_POWER_SUPPLY
164static const char * const tusb1210_chg_det_states[] = {
165 "CHG_DET_CONNECTING",
166 "CHG_DET_START_DET",
167 "CHG_DET_READ_DET",
168 "CHG_DET_FINISH_DET",
169 "CHG_DET_CONNECTED",
170 "CHG_DET_DISCONNECTING",
171 "CHG_DET_DISCONNECTING_DONE",
172 "CHG_DET_DISCONNECTED",
173};
174
175static void tusb1210_reset(struct tusb1210 *tusb)
176{
177 gpiod_set_value_cansleep(tusb->gpio_reset, 0);
178 usleep_range(200, 500);
179 gpiod_set_value_cansleep(tusb->gpio_reset, 1);
180}
181
182static void tusb1210_chg_det_set_type(struct tusb1210 *tusb,
183 enum power_supply_usb_type type)
184{
185 dev_dbg(tusb->dev, "charger type: %d\n", type);
186 tusb->chg_type = type;
187 tusb->chg_det_retries = 0;
188 power_supply_changed(tusb->psy);
189}
190
191static void tusb1210_chg_det_set_state(struct tusb1210 *tusb,
192 enum tusb1210_chg_det_state new_state,
193 int delay_ms)
194{
195 if (delay_ms)
196 dev_dbg(tusb->dev, "chg_det new state %s in %d ms\n",
197 tusb1210_chg_det_states[new_state], delay_ms);
198
199 tusb->chg_det_state = new_state;
200 mod_delayed_work(system_long_wq, &tusb->chg_det_work,
201 msecs_to_jiffies(delay_ms));
202}
203
204static void tusb1210_chg_det_handle_ulpi_error(struct tusb1210 *tusb)
205{
206 tusb1210_reset(tusb);
207 if (tusb->chg_det_retries < TUSB1210_CHG_DET_MAX_RETRIES) {
208 tusb->chg_det_retries++;
209 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET,
210 TUSB1210_RESET_TIME_MS);
211 } else {
212 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET,
213 TUSB1210_RESET_TIME_MS);
214 }
215}
216
217/*
218 * Boards using a TUSB121x for charger-detection have 3 power_supply class devs:
219 *
220 * tusb1211-charger-detect(1) -> charger -> fuel-gauge
221 *
222 * To determine if an USB charger is connected to the board, the online prop of
223 * the charger psy needs to be read. Since the tusb1211-charger-detect psy is
224 * the start of the supplier -> supplied-to chain, power_supply_am_i_supplied()
225 * cannot be used here.
226 *
227 * Instead, below is a list of the power_supply names of known chargers for
228 * these boards and the charger psy is looked up by name from this list.
229 *
230 * (1) modelling the external USB charger
231 */
232static const char * const tusb1210_chargers[] = {
233 "bq24190-charger",
234};
235
236static bool tusb1210_get_online(struct tusb1210 *tusb)
237{
238 struct power_supply *charger = NULL;
239 union power_supply_propval val;
240 bool online = false;
241 int i, ret;
242
243 for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !charger; i++)
244 charger = power_supply_get_by_name(tusb1210_chargers[i]);
245
246 if (!charger)
247 return false;
248
249 ret = power_supply_get_property(charger, POWER_SUPPLY_PROP_ONLINE, &val);
250 if (ret == 0)
251 online = val.intval;
252
253 power_supply_put(charger);
254
255 return online;
256}
257
258static void tusb1210_chg_det_work(struct work_struct *work)
259{
260 struct tusb1210 *tusb = container_of(work, struct tusb1210, chg_det_work.work);
261 bool vbus_present = tusb1210_get_online(tusb);
262 int ret;
263 u8 val;
264
265 dev_dbg(tusb->dev, "chg_det state %s vbus_present %d\n",
266 tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
267
268 switch (tusb->chg_det_state) {
269 case TUSB1210_CHG_DET_CONNECTING:
270 tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
271 tusb->chg_det_retries = 0;
272 /* Power on USB controller for ulpi_read()/_write() */
273 ret = pm_runtime_resume_and_get(tusb->dev->parent);
274 if (ret < 0) {
275 dev_err(tusb->dev, "error %d runtime-resuming\n", ret);
276 /* Should never happen, skip charger detection */
277 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
278 return;
279 }
280 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0);
281 break;
282 case TUSB1210_CHG_DET_START_DET:
283 /*
284 * Use the builtin charger detection FSM to keep things simple.
285 * This only detects DCP / SDP. This is good enough for the few
286 * boards which actually rely on the phy for charger detection.
287 */
288 mutex_lock(&tusb->phy->mutex);
289 ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
290 TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
291 mutex_unlock(&tusb->phy->mutex);
292 if (ret) {
293 tusb1210_chg_det_handle_ulpi_error(tusb);
294 break;
295 }
296
297 /* Wait 400 ms for the charger detection FSM to finish */
298 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400);
299 break;
300 case TUSB1210_CHG_DET_READ_DET:
301 mutex_lock(&tusb->phy->mutex);
302 ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
303 mutex_unlock(&tusb->phy->mutex);
304 if (ret) {
305 tusb1210_chg_det_handle_ulpi_error(tusb);
306 break;
307 }
308
309 if (val & TUSB1211_POWER_CONTROL_DET_COMP)
310 tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP);
311 else
312 tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
313
314 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0);
315 break;
316 case TUSB1210_CHG_DET_FINISH_DET:
317 mutex_lock(&tusb->phy->mutex);
318
319 /* Set SW_CONTROL to stop the charger-det FSM */
320 ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
321 TUSB1211_POWER_CONTROL_SW_CONTROL);
322
323 /* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
324 ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
325 TUSB1211_POWER_CONTROL_DP_VSRC_EN);
326
327 /* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
328 ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
329 TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
330
331 /* If any of the above fails reset the phy */
332 if (ret) {
333 tusb1210_reset(tusb);
334 msleep(TUSB1210_RESET_TIME_MS);
335 }
336
337 /* Restore phy-parameters and OTG_CTRL register */
338 tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, tusb->otg_ctrl);
339 tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
340 tusb->vendor_specific2);
341
342 mutex_unlock(&tusb->phy->mutex);
343
344 pm_runtime_put(tusb->dev->parent);
345 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
346 break;
347 case TUSB1210_CHG_DET_CONNECTED:
348 if (!vbus_present)
349 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0);
350 break;
351 case TUSB1210_CHG_DET_DISCONNECTING:
352 /*
353 * The phy seems to take approx. 600ms longer then the charger
354 * chip (which is used to get vbus_present) to determine Vbus
355 * session end. Wait 800ms to ensure the phy has detected and
356 * signalled Vbus session end.
357 */
358 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800);
359 break;
360 case TUSB1210_CHG_DET_DISCONNECTING_DONE:
361 /*
362 * The phy often stops reacting to ulpi_read()/_write requests
363 * after a Vbus-session end. Reset it to work around this.
364 */
365 tusb1210_reset(tusb);
366 tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
367 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0);
368 break;
369 case TUSB1210_CHG_DET_DISCONNECTED:
370 if (vbus_present)
371 tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0);
372 break;
373 }
374}
375
376static int tusb1210_psy_notifier(struct notifier_block *nb,
377 unsigned long event, void *ptr)
378{
379 struct tusb1210 *tusb = container_of(nb, struct tusb1210, psy_nb);
380 struct power_supply *psy = ptr;
381
382 if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB)
383 queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0);
384
385 return NOTIFY_OK;
386}
387
388static int tusb1210_psy_get_prop(struct power_supply *psy,
389 enum power_supply_property psp,
390 union power_supply_propval *val)
391{
392 struct tusb1210 *tusb = power_supply_get_drvdata(psy);
393
394 switch (psp) {
395 case POWER_SUPPLY_PROP_ONLINE:
396 val->intval = tusb1210_get_online(tusb);
397 break;
398 case POWER_SUPPLY_PROP_USB_TYPE:
399 val->intval = tusb->chg_type;
400 break;
401 case POWER_SUPPLY_PROP_CURRENT_MAX:
402 if (tusb->chg_type == POWER_SUPPLY_USB_TYPE_DCP)
403 val->intval = 2000000;
404 else
405 val->intval = 500000;
406 break;
407 default:
408 return -EINVAL;
409 }
410
411 return 0;
412}
413
414static const enum power_supply_property tusb1210_psy_props[] = {
415 POWER_SUPPLY_PROP_ONLINE,
416 POWER_SUPPLY_PROP_USB_TYPE,
417 POWER_SUPPLY_PROP_CURRENT_MAX,
418};
419
420static const struct power_supply_desc tusb1210_psy_desc = {
421 .name = "tusb1211-charger-detect",
422 .type = POWER_SUPPLY_TYPE_USB,
423 .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) |
424 BIT(POWER_SUPPLY_USB_TYPE_DCP) |
425 BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
426 .properties = tusb1210_psy_props,
427 .num_properties = ARRAY_SIZE(tusb1210_psy_props),
428 .get_property = tusb1210_psy_get_prop,
429};
430
431/* Setup charger detection if requested, on errors continue without chg-det */
432static void tusb1210_probe_charger_detect(struct tusb1210 *tusb)
433{
434 struct power_supply_config psy_cfg = { .drv_data = tusb };
435 struct device *dev = tusb->dev;
436 struct ulpi *ulpi = to_ulpi_dev(dev);
437 int ret;
438
439 if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect"))
440 return;
441
442 if (ulpi->id.product != TI_DEVICE_TUSB1211) {
443 dev_err(dev, "error charger detection is only supported on the TUSB1211\n");
444 return;
445 }
446
447 ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl);
448 if (ret)
449 return;
450
451 tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg);
452 if (IS_ERR(tusb->psy))
453 return;
454
455 /*
456 * Delay initial run by 2 seconds to allow the charger driver,
457 * which is used to determine vbus_present, to load.
458 */
459 tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
460 INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
461 queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
462
463 tusb->psy_nb.notifier_call = tusb1210_psy_notifier;
464 power_supply_reg_notifier(&tusb->psy_nb);
465}
466
467static void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
468{
469
470 if (!IS_ERR_OR_NULL(tusb->psy)) {
471 power_supply_unreg_notifier(&tusb->psy_nb);
472 cancel_delayed_work_sync(&tusb->chg_det_work);
473 power_supply_unregister(tusb->psy);
474 }
475}
476#else
477static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }
478static void tusb1210_remove_charger_detect(struct tusb1210 *tusb) { }
479#endif
480
481static const struct phy_ops phy_ops = {
482 .power_on = tusb1210_power_on,
483 .power_off = tusb1210_power_off,
484 .set_mode = tusb1210_set_mode,
485 .owner = THIS_MODULE,
486};
487
488static int tusb1210_probe(struct ulpi *ulpi)
489{
490 struct device *dev = &ulpi->dev;
491 struct tusb1210 *tusb;
492 u8 val, reg;
493 int ret;
494
495 tusb = devm_kzalloc(dev, sizeof(*tusb), GFP_KERNEL);
496 if (!tusb)
497 return -ENOMEM;
498
499 tusb->dev = dev;
500
501 tusb->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
502 if (IS_ERR(tusb->gpio_reset))
503 return PTR_ERR(tusb->gpio_reset);
504
505 gpiod_set_value_cansleep(tusb->gpio_reset, 1);
506
507 tusb->gpio_cs = devm_gpiod_get_optional(dev, "cs", GPIOD_OUT_LOW);
508 if (IS_ERR(tusb->gpio_cs))
509 return PTR_ERR(tusb->gpio_cs);
510
511 gpiod_set_value_cansleep(tusb->gpio_cs, 1);
512
513 /*
514 * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
515 * diagram optimization and DP/DM swap.
516 */
517
518 ret = tusb1210_ulpi_read(tusb, TUSB1210_VENDOR_SPECIFIC2, ®);
519 if (ret)
520 return ret;
521
522 /* High speed output drive strength configuration */
523 if (!device_property_read_u8(dev, "ihstx", &val))
524 u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK);
525
526 /* High speed output impedance configuration */
527 if (!device_property_read_u8(dev, "zhsdrv", &val))
528 u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK);
529
530 /* DP/DM swap control */
531 if (!device_property_read_u8(dev, "datapolarity", &val))
532 u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
533
534 ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg);
535 if (ret)
536 return ret;
537
538 tusb->vendor_specific2 = reg;
539
540 tusb1210_probe_charger_detect(tusb);
541
542 tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
543 if (IS_ERR(tusb->phy)) {
544 ret = PTR_ERR(tusb->phy);
545 goto err_remove_charger;
546 }
547
548 phy_set_drvdata(tusb->phy, tusb);
549 ulpi_set_drvdata(ulpi, tusb);
550 return 0;
551
552err_remove_charger:
553 tusb1210_remove_charger_detect(tusb);
554 return ret;
555}
556
557static void tusb1210_remove(struct ulpi *ulpi)
558{
559 struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
560
561 ulpi_phy_destroy(ulpi, tusb->phy);
562 tusb1210_remove_charger_detect(tusb);
563}
564
565static const struct ulpi_device_id tusb1210_ulpi_id[] = {
566 { TI_VENDOR_ID, TI_DEVICE_TUSB1210 },
567 { TI_VENDOR_ID, TI_DEVICE_TUSB1211 },
568 { },
569};
570MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
571
572static struct ulpi_driver tusb1210_driver = {
573 .id_table = tusb1210_ulpi_id,
574 .probe = tusb1210_probe,
575 .remove = tusb1210_remove,
576 .driver = {
577 .name = "tusb1210",
578 .owner = THIS_MODULE,
579 },
580};
581
582module_ulpi_driver(tusb1210_driver);
583
584MODULE_AUTHOR("Intel Corporation");
585MODULE_LICENSE("GPL v2");
586MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");