162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * tusb1210.c - TUSB1210 USB ULPI PHY driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015 Intel Corporation
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/ulpi/driver.h>
1362306a36Sopenharmony_ci#include <linux/ulpi/regs.h>
1462306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1562306a36Sopenharmony_ci#include <linux/phy/ulpi_phy.h>
1662306a36Sopenharmony_ci#include <linux/power_supply.h>
1762306a36Sopenharmony_ci#include <linux/property.h>
1862306a36Sopenharmony_ci#include <linux/workqueue.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define TUSB1211_POWER_CONTROL				0x3d
2162306a36Sopenharmony_ci#define TUSB1211_POWER_CONTROL_SET			0x3e
2262306a36Sopenharmony_ci#define TUSB1211_POWER_CONTROL_CLEAR			0x3f
2362306a36Sopenharmony_ci#define TUSB1211_POWER_CONTROL_SW_CONTROL		BIT(0)
2462306a36Sopenharmony_ci#define TUSB1211_POWER_CONTROL_DET_COMP			BIT(1)
2562306a36Sopenharmony_ci#define TUSB1211_POWER_CONTROL_DP_VSRC_EN		BIT(6)
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define TUSB1210_VENDOR_SPECIFIC2			0x80
2862306a36Sopenharmony_ci#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK		GENMASK(3, 0)
2962306a36Sopenharmony_ci#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK		GENMASK(5, 4)
3062306a36Sopenharmony_ci#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK		BIT(6)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define TUSB1211_VENDOR_SPECIFIC3			0x85
3362306a36Sopenharmony_ci#define TUSB1211_VENDOR_SPECIFIC3_SET			0x86
3462306a36Sopenharmony_ci#define TUSB1211_VENDOR_SPECIFIC3_CLEAR			0x87
3562306a36Sopenharmony_ci#define TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET		BIT(4)
3662306a36Sopenharmony_ci#define TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN	BIT(6)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define TUSB1210_RESET_TIME_MS				50
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define TUSB1210_CHG_DET_MAX_RETRIES			5
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* TUSB1210 charger detection work states */
4362306a36Sopenharmony_cienum tusb1210_chg_det_state {
4462306a36Sopenharmony_ci	TUSB1210_CHG_DET_CONNECTING,
4562306a36Sopenharmony_ci	TUSB1210_CHG_DET_START_DET,
4662306a36Sopenharmony_ci	TUSB1210_CHG_DET_READ_DET,
4762306a36Sopenharmony_ci	TUSB1210_CHG_DET_FINISH_DET,
4862306a36Sopenharmony_ci	TUSB1210_CHG_DET_CONNECTED,
4962306a36Sopenharmony_ci	TUSB1210_CHG_DET_DISCONNECTING,
5062306a36Sopenharmony_ci	TUSB1210_CHG_DET_DISCONNECTING_DONE,
5162306a36Sopenharmony_ci	TUSB1210_CHG_DET_DISCONNECTED,
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistruct tusb1210 {
5562306a36Sopenharmony_ci	struct ulpi *ulpi;
5662306a36Sopenharmony_ci	struct phy *phy;
5762306a36Sopenharmony_ci	struct gpio_desc *gpio_reset;
5862306a36Sopenharmony_ci	struct gpio_desc *gpio_cs;
5962306a36Sopenharmony_ci	u8 otg_ctrl;
6062306a36Sopenharmony_ci	u8 vendor_specific2;
6162306a36Sopenharmony_ci#ifdef CONFIG_POWER_SUPPLY
6262306a36Sopenharmony_ci	enum power_supply_usb_type chg_type;
6362306a36Sopenharmony_ci	enum tusb1210_chg_det_state chg_det_state;
6462306a36Sopenharmony_ci	int chg_det_retries;
6562306a36Sopenharmony_ci	struct delayed_work chg_det_work;
6662306a36Sopenharmony_ci	struct notifier_block psy_nb;
6762306a36Sopenharmony_ci	struct power_supply *psy;
6862306a36Sopenharmony_ci	struct power_supply *charger;
6962306a36Sopenharmony_ci#endif
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	int ret;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	ret = ulpi_write(tusb->ulpi, reg, val);
7762306a36Sopenharmony_ci	if (ret)
7862306a36Sopenharmony_ci		dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n",
7962306a36Sopenharmony_ci			ret, val, reg);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return ret;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	int ret;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = ulpi_read(tusb->ulpi, reg);
8962306a36Sopenharmony_ci	if (ret >= 0) {
9062306a36Sopenharmony_ci		*val = ret;
9162306a36Sopenharmony_ci		ret = 0;
9262306a36Sopenharmony_ci	} else {
9362306a36Sopenharmony_ci		dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return ret;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic int tusb1210_power_on(struct phy *phy)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct tusb1210 *tusb = phy_get_drvdata(phy);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
10462306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	msleep(TUSB1210_RESET_TIME_MS);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* Restore the optional eye diagram optimization value */
10962306a36Sopenharmony_ci	tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, tusb->vendor_specific2);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int tusb1210_power_off(struct phy *phy)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct tusb1210 *tusb = phy_get_drvdata(phy);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_reset, 0);
11962306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_cs, 0);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return 0;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct tusb1210 *tusb = phy_get_drvdata(phy);
12762306a36Sopenharmony_ci	int ret;
12862306a36Sopenharmony_ci	u8 reg;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &reg);
13162306a36Sopenharmony_ci	if (ret < 0)
13262306a36Sopenharmony_ci		return ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	switch (mode) {
13562306a36Sopenharmony_ci	case PHY_MODE_USB_HOST:
13662306a36Sopenharmony_ci		reg |= (ULPI_OTG_CTRL_DRVVBUS_EXT
13762306a36Sopenharmony_ci			| ULPI_OTG_CTRL_ID_PULLUP
13862306a36Sopenharmony_ci			| ULPI_OTG_CTRL_DP_PULLDOWN
13962306a36Sopenharmony_ci			| ULPI_OTG_CTRL_DM_PULLDOWN);
14062306a36Sopenharmony_ci		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
14162306a36Sopenharmony_ci		reg |= ULPI_OTG_CTRL_DRVVBUS;
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	case PHY_MODE_USB_DEVICE:
14462306a36Sopenharmony_ci		reg &= ~(ULPI_OTG_CTRL_DRVVBUS
14562306a36Sopenharmony_ci			 | ULPI_OTG_CTRL_DP_PULLDOWN
14662306a36Sopenharmony_ci			 | ULPI_OTG_CTRL_DM_PULLDOWN);
14762306a36Sopenharmony_ci		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
14862306a36Sopenharmony_ci		reg &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci	default:
15162306a36Sopenharmony_ci		/* nothing */
15262306a36Sopenharmony_ci		return 0;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	tusb->otg_ctrl = reg;
15662306a36Sopenharmony_ci	return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci#ifdef CONFIG_POWER_SUPPLY
16062306a36Sopenharmony_cistatic const char * const tusb1210_chg_det_states[] = {
16162306a36Sopenharmony_ci	"CHG_DET_CONNECTING",
16262306a36Sopenharmony_ci	"CHG_DET_START_DET",
16362306a36Sopenharmony_ci	"CHG_DET_READ_DET",
16462306a36Sopenharmony_ci	"CHG_DET_FINISH_DET",
16562306a36Sopenharmony_ci	"CHG_DET_CONNECTED",
16662306a36Sopenharmony_ci	"CHG_DET_DISCONNECTING",
16762306a36Sopenharmony_ci	"CHG_DET_DISCONNECTING_DONE",
16862306a36Sopenharmony_ci	"CHG_DET_DISCONNECTED",
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void tusb1210_reset(struct tusb1210 *tusb)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_reset, 0);
17462306a36Sopenharmony_ci	usleep_range(200, 500);
17562306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic void tusb1210_chg_det_set_type(struct tusb1210 *tusb,
17962306a36Sopenharmony_ci				      enum power_supply_usb_type type)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type);
18262306a36Sopenharmony_ci	tusb->chg_type = type;
18362306a36Sopenharmony_ci	tusb->chg_det_retries = 0;
18462306a36Sopenharmony_ci	power_supply_changed(tusb->psy);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic void tusb1210_chg_det_set_state(struct tusb1210 *tusb,
18862306a36Sopenharmony_ci				       enum tusb1210_chg_det_state new_state,
18962306a36Sopenharmony_ci				       int delay_ms)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	if (delay_ms)
19262306a36Sopenharmony_ci		dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n",
19362306a36Sopenharmony_ci			tusb1210_chg_det_states[new_state], delay_ms);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	tusb->chg_det_state = new_state;
19662306a36Sopenharmony_ci	mod_delayed_work(system_long_wq, &tusb->chg_det_work,
19762306a36Sopenharmony_ci			 msecs_to_jiffies(delay_ms));
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void tusb1210_chg_det_handle_ulpi_error(struct tusb1210 *tusb)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	tusb1210_reset(tusb);
20362306a36Sopenharmony_ci	if (tusb->chg_det_retries < TUSB1210_CHG_DET_MAX_RETRIES) {
20462306a36Sopenharmony_ci		tusb->chg_det_retries++;
20562306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET,
20662306a36Sopenharmony_ci					   TUSB1210_RESET_TIME_MS);
20762306a36Sopenharmony_ci	} else {
20862306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET,
20962306a36Sopenharmony_ci					   TUSB1210_RESET_TIME_MS);
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*
21462306a36Sopenharmony_ci * Boards using a TUSB121x for charger-detection have 3 power_supply class devs:
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci * tusb1211-charger-detect(1) -> charger -> fuel-gauge
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * To determine if an USB charger is connected to the board, the online prop of
21962306a36Sopenharmony_ci * the charger psy needs to be read. Since the tusb1211-charger-detect psy is
22062306a36Sopenharmony_ci * the start of the supplier -> supplied-to chain, power_supply_am_i_supplied()
22162306a36Sopenharmony_ci * cannot be used here.
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * Instead, below is a list of the power_supply names of known chargers for
22462306a36Sopenharmony_ci * these boards and the charger psy is looked up by name from this list.
22562306a36Sopenharmony_ci *
22662306a36Sopenharmony_ci * (1) modelling the external USB charger
22762306a36Sopenharmony_ci */
22862306a36Sopenharmony_cistatic const char * const tusb1210_chargers[] = {
22962306a36Sopenharmony_ci	"bq24190-charger",
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic bool tusb1210_get_online(struct tusb1210 *tusb)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	union power_supply_propval val;
23562306a36Sopenharmony_ci	int i;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !tusb->charger; i++)
23862306a36Sopenharmony_ci		tusb->charger = power_supply_get_by_name(tusb1210_chargers[i]);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (!tusb->charger)
24162306a36Sopenharmony_ci		return false;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (power_supply_get_property(tusb->charger, POWER_SUPPLY_PROP_ONLINE, &val))
24462306a36Sopenharmony_ci		return false;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return val.intval;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void tusb1210_chg_det_work(struct work_struct *work)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct tusb1210 *tusb = container_of(work, struct tusb1210, chg_det_work.work);
25262306a36Sopenharmony_ci	bool vbus_present = tusb1210_get_online(tusb);
25362306a36Sopenharmony_ci	int ret;
25462306a36Sopenharmony_ci	u8 val;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n",
25762306a36Sopenharmony_ci		tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	switch (tusb->chg_det_state) {
26062306a36Sopenharmony_ci	case TUSB1210_CHG_DET_CONNECTING:
26162306a36Sopenharmony_ci		tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
26262306a36Sopenharmony_ci		tusb->chg_det_retries = 0;
26362306a36Sopenharmony_ci		/* Power on USB controller for ulpi_read()/_write() */
26462306a36Sopenharmony_ci		ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent);
26562306a36Sopenharmony_ci		if (ret < 0) {
26662306a36Sopenharmony_ci			dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret);
26762306a36Sopenharmony_ci			/* Should never happen, skip charger detection */
26862306a36Sopenharmony_ci			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
26962306a36Sopenharmony_ci			return;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0);
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	case TUSB1210_CHG_DET_START_DET:
27462306a36Sopenharmony_ci		/*
27562306a36Sopenharmony_ci		 * Use the builtin charger detection FSM to keep things simple.
27662306a36Sopenharmony_ci		 * This only detects DCP / SDP. This is good enough for the few
27762306a36Sopenharmony_ci		 * boards which actually rely on the phy for charger detection.
27862306a36Sopenharmony_ci		 */
27962306a36Sopenharmony_ci		mutex_lock(&tusb->phy->mutex);
28062306a36Sopenharmony_ci		ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
28162306a36Sopenharmony_ci					  TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
28262306a36Sopenharmony_ci		mutex_unlock(&tusb->phy->mutex);
28362306a36Sopenharmony_ci		if (ret) {
28462306a36Sopenharmony_ci			tusb1210_chg_det_handle_ulpi_error(tusb);
28562306a36Sopenharmony_ci			break;
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		/* Wait 400 ms for the charger detection FSM to finish */
28962306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400);
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci	case TUSB1210_CHG_DET_READ_DET:
29262306a36Sopenharmony_ci		mutex_lock(&tusb->phy->mutex);
29362306a36Sopenharmony_ci		ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
29462306a36Sopenharmony_ci		mutex_unlock(&tusb->phy->mutex);
29562306a36Sopenharmony_ci		if (ret) {
29662306a36Sopenharmony_ci			tusb1210_chg_det_handle_ulpi_error(tusb);
29762306a36Sopenharmony_ci			break;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		if (val & TUSB1211_POWER_CONTROL_DET_COMP)
30162306a36Sopenharmony_ci			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP);
30262306a36Sopenharmony_ci		else
30362306a36Sopenharmony_ci			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0);
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	case TUSB1210_CHG_DET_FINISH_DET:
30862306a36Sopenharmony_ci		mutex_lock(&tusb->phy->mutex);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		/* Set SW_CONTROL to stop the charger-det FSM */
31162306a36Sopenharmony_ci		ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
31262306a36Sopenharmony_ci					  TUSB1211_POWER_CONTROL_SW_CONTROL);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		/* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
31562306a36Sopenharmony_ci		ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
31662306a36Sopenharmony_ci					   TUSB1211_POWER_CONTROL_DP_VSRC_EN);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		/* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
31962306a36Sopenharmony_ci		ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
32062306a36Sopenharmony_ci					   TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		/* If any of the above fails reset the phy */
32362306a36Sopenharmony_ci		if (ret) {
32462306a36Sopenharmony_ci			tusb1210_reset(tusb);
32562306a36Sopenharmony_ci			msleep(TUSB1210_RESET_TIME_MS);
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		/* Restore phy-parameters and OTG_CTRL register */
32962306a36Sopenharmony_ci		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, tusb->otg_ctrl);
33062306a36Sopenharmony_ci		tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
33162306a36Sopenharmony_ci				    tusb->vendor_specific2);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		mutex_unlock(&tusb->phy->mutex);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		pm_runtime_put(tusb->ulpi->dev.parent);
33662306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
33762306a36Sopenharmony_ci		break;
33862306a36Sopenharmony_ci	case TUSB1210_CHG_DET_CONNECTED:
33962306a36Sopenharmony_ci		if (!vbus_present)
34062306a36Sopenharmony_ci			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0);
34162306a36Sopenharmony_ci		break;
34262306a36Sopenharmony_ci	case TUSB1210_CHG_DET_DISCONNECTING:
34362306a36Sopenharmony_ci		/*
34462306a36Sopenharmony_ci		 * The phy seems to take approx. 600ms longer then the charger
34562306a36Sopenharmony_ci		 * chip (which is used to get vbus_present) to determine Vbus
34662306a36Sopenharmony_ci		 * session end. Wait 800ms to ensure the phy has detected and
34762306a36Sopenharmony_ci		 * signalled Vbus session end.
34862306a36Sopenharmony_ci		 */
34962306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800);
35062306a36Sopenharmony_ci		break;
35162306a36Sopenharmony_ci	case TUSB1210_CHG_DET_DISCONNECTING_DONE:
35262306a36Sopenharmony_ci		/*
35362306a36Sopenharmony_ci		 * The phy often stops reacting to ulpi_read()/_write requests
35462306a36Sopenharmony_ci		 * after a Vbus-session end. Reset it to work around this.
35562306a36Sopenharmony_ci		 */
35662306a36Sopenharmony_ci		tusb1210_reset(tusb);
35762306a36Sopenharmony_ci		tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
35862306a36Sopenharmony_ci		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0);
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	case TUSB1210_CHG_DET_DISCONNECTED:
36162306a36Sopenharmony_ci		if (vbus_present)
36262306a36Sopenharmony_ci			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0);
36362306a36Sopenharmony_ci		break;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic int tusb1210_psy_notifier(struct notifier_block *nb,
36862306a36Sopenharmony_ci	unsigned long event, void *ptr)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct tusb1210 *tusb = container_of(nb, struct tusb1210, psy_nb);
37162306a36Sopenharmony_ci	struct power_supply *psy = ptr;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB)
37462306a36Sopenharmony_ci		queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return NOTIFY_OK;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic int tusb1210_psy_get_prop(struct power_supply *psy,
38062306a36Sopenharmony_ci				 enum power_supply_property psp,
38162306a36Sopenharmony_ci				 union power_supply_propval *val)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct tusb1210 *tusb = power_supply_get_drvdata(psy);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	switch (psp) {
38662306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_ONLINE:
38762306a36Sopenharmony_ci		val->intval = tusb1210_get_online(tusb);
38862306a36Sopenharmony_ci		break;
38962306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_USB_TYPE:
39062306a36Sopenharmony_ci		val->intval = tusb->chg_type;
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case POWER_SUPPLY_PROP_CURRENT_MAX:
39362306a36Sopenharmony_ci		if (tusb->chg_type == POWER_SUPPLY_USB_TYPE_DCP)
39462306a36Sopenharmony_ci			val->intval = 2000000;
39562306a36Sopenharmony_ci		else
39662306a36Sopenharmony_ci			val->intval = 500000;
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	default:
39962306a36Sopenharmony_ci		return -EINVAL;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic const enum power_supply_usb_type tusb1210_psy_usb_types[] = {
40662306a36Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_SDP,
40762306a36Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_DCP,
40862306a36Sopenharmony_ci	POWER_SUPPLY_USB_TYPE_UNKNOWN,
40962306a36Sopenharmony_ci};
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic const enum power_supply_property tusb1210_psy_props[] = {
41262306a36Sopenharmony_ci	POWER_SUPPLY_PROP_ONLINE,
41362306a36Sopenharmony_ci	POWER_SUPPLY_PROP_USB_TYPE,
41462306a36Sopenharmony_ci	POWER_SUPPLY_PROP_CURRENT_MAX,
41562306a36Sopenharmony_ci};
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic const struct power_supply_desc tusb1210_psy_desc = {
41862306a36Sopenharmony_ci	.name = "tusb1211-charger-detect",
41962306a36Sopenharmony_ci	.type = POWER_SUPPLY_TYPE_USB,
42062306a36Sopenharmony_ci	.usb_types = tusb1210_psy_usb_types,
42162306a36Sopenharmony_ci	.num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types),
42262306a36Sopenharmony_ci	.properties = tusb1210_psy_props,
42362306a36Sopenharmony_ci	.num_properties = ARRAY_SIZE(tusb1210_psy_props),
42462306a36Sopenharmony_ci	.get_property = tusb1210_psy_get_prop,
42562306a36Sopenharmony_ci};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/* Setup charger detection if requested, on errors continue without chg-det */
42862306a36Sopenharmony_cistatic void tusb1210_probe_charger_detect(struct tusb1210 *tusb)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct power_supply_config psy_cfg = { .drv_data = tusb };
43162306a36Sopenharmony_ci	struct device *dev = &tusb->ulpi->dev;
43262306a36Sopenharmony_ci	int ret;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect"))
43562306a36Sopenharmony_ci		return;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (tusb->ulpi->id.product != 0x1508) {
43862306a36Sopenharmony_ci		dev_err(dev, "error charger detection is only supported on the TUSB1211\n");
43962306a36Sopenharmony_ci		return;
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl);
44362306a36Sopenharmony_ci	if (ret)
44462306a36Sopenharmony_ci		return;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg);
44762306a36Sopenharmony_ci	if (IS_ERR(tusb->psy))
44862306a36Sopenharmony_ci		return;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/*
45162306a36Sopenharmony_ci	 * Delay initial run by 2 seconds to allow the charger driver,
45262306a36Sopenharmony_ci	 * which is used to determine vbus_present, to load.
45362306a36Sopenharmony_ci	 */
45462306a36Sopenharmony_ci	tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
45562306a36Sopenharmony_ci	INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
45662306a36Sopenharmony_ci	queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	tusb->psy_nb.notifier_call = tusb1210_psy_notifier;
45962306a36Sopenharmony_ci	power_supply_reg_notifier(&tusb->psy_nb);
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(tusb->psy)) {
46662306a36Sopenharmony_ci		power_supply_unreg_notifier(&tusb->psy_nb);
46762306a36Sopenharmony_ci		cancel_delayed_work_sync(&tusb->chg_det_work);
46862306a36Sopenharmony_ci		power_supply_unregister(tusb->psy);
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (tusb->charger)
47262306a36Sopenharmony_ci		power_supply_put(tusb->charger);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci#else
47562306a36Sopenharmony_cistatic void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }
47662306a36Sopenharmony_cistatic void tusb1210_remove_charger_detect(struct tusb1210 *tusb) { }
47762306a36Sopenharmony_ci#endif
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic const struct phy_ops phy_ops = {
48062306a36Sopenharmony_ci	.power_on = tusb1210_power_on,
48162306a36Sopenharmony_ci	.power_off = tusb1210_power_off,
48262306a36Sopenharmony_ci	.set_mode = tusb1210_set_mode,
48362306a36Sopenharmony_ci	.owner = THIS_MODULE,
48462306a36Sopenharmony_ci};
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic int tusb1210_probe(struct ulpi *ulpi)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct tusb1210 *tusb;
48962306a36Sopenharmony_ci	u8 val, reg;
49062306a36Sopenharmony_ci	int ret;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
49362306a36Sopenharmony_ci	if (!tusb)
49462306a36Sopenharmony_ci		return -ENOMEM;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	tusb->ulpi = ulpi;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
49962306a36Sopenharmony_ci						   GPIOD_OUT_LOW);
50062306a36Sopenharmony_ci	if (IS_ERR(tusb->gpio_reset))
50162306a36Sopenharmony_ci		return PTR_ERR(tusb->gpio_reset);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs",
50662306a36Sopenharmony_ci						GPIOD_OUT_LOW);
50762306a36Sopenharmony_ci	if (IS_ERR(tusb->gpio_cs))
50862306a36Sopenharmony_ci		return PTR_ERR(tusb->gpio_cs);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/*
51362306a36Sopenharmony_ci	 * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
51462306a36Sopenharmony_ci	 * diagram optimization and DP/DM swap.
51562306a36Sopenharmony_ci	 */
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	ret = tusb1210_ulpi_read(tusb, TUSB1210_VENDOR_SPECIFIC2, &reg);
51862306a36Sopenharmony_ci	if (ret)
51962306a36Sopenharmony_ci		return ret;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* High speed output drive strength configuration */
52262306a36Sopenharmony_ci	if (!device_property_read_u8(&ulpi->dev, "ihstx", &val))
52362306a36Sopenharmony_ci		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* High speed output impedance configuration */
52662306a36Sopenharmony_ci	if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val))
52762306a36Sopenharmony_ci		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* DP/DM swap control */
53062306a36Sopenharmony_ci	if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val))
53162306a36Sopenharmony_ci		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg);
53462306a36Sopenharmony_ci	if (ret)
53562306a36Sopenharmony_ci		return ret;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	tusb->vendor_specific2 = reg;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	tusb1210_probe_charger_detect(tusb);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
54262306a36Sopenharmony_ci	if (IS_ERR(tusb->phy)) {
54362306a36Sopenharmony_ci		ret = PTR_ERR(tusb->phy);
54462306a36Sopenharmony_ci		goto err_remove_charger;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	phy_set_drvdata(tusb->phy, tusb);
54862306a36Sopenharmony_ci	ulpi_set_drvdata(ulpi, tusb);
54962306a36Sopenharmony_ci	return 0;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cierr_remove_charger:
55262306a36Sopenharmony_ci	tusb1210_remove_charger_detect(tusb);
55362306a36Sopenharmony_ci	return ret;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic void tusb1210_remove(struct ulpi *ulpi)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ulpi_phy_destroy(ulpi, tusb->phy);
56162306a36Sopenharmony_ci	tusb1210_remove_charger_detect(tusb);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci#define TI_VENDOR_ID 0x0451
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic const struct ulpi_device_id tusb1210_ulpi_id[] = {
56762306a36Sopenharmony_ci	{ TI_VENDOR_ID, 0x1507, },  /* TUSB1210 */
56862306a36Sopenharmony_ci	{ TI_VENDOR_ID, 0x1508, },  /* TUSB1211 */
56962306a36Sopenharmony_ci	{ },
57062306a36Sopenharmony_ci};
57162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic struct ulpi_driver tusb1210_driver = {
57462306a36Sopenharmony_ci	.id_table = tusb1210_ulpi_id,
57562306a36Sopenharmony_ci	.probe = tusb1210_probe,
57662306a36Sopenharmony_ci	.remove = tusb1210_remove,
57762306a36Sopenharmony_ci	.driver = {
57862306a36Sopenharmony_ci		.name = "tusb1210",
57962306a36Sopenharmony_ci		.owner = THIS_MODULE,
58062306a36Sopenharmony_ci	},
58162306a36Sopenharmony_ci};
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cimodule_ulpi_driver(tusb1210_driver);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ciMODULE_AUTHOR("Intel Corporation");
58662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
58762306a36Sopenharmony_ciMODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
588