xref: /openbmc/linux/drivers/phy/ti/phy-tusb1210.c (revision 73224a5d)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2466b1516SVinod Koul /*
30b56e9a7SVivek Gautam  * tusb1210.c - TUSB1210 USB ULPI PHY driver
40b56e9a7SVivek Gautam  *
50b56e9a7SVivek Gautam  * Copyright (C) 2015 Intel Corporation
60b56e9a7SVivek Gautam  *
70b56e9a7SVivek Gautam  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
80b56e9a7SVivek Gautam  */
90b56e9a7SVivek Gautam #include <linux/module.h>
10eb445a15SLiam Beguin #include <linux/bitfield.h>
11df37c998SHans de Goede #include <linux/delay.h>
120b56e9a7SVivek Gautam #include <linux/ulpi/driver.h>
1354fe3088SFelipe Balbi #include <linux/ulpi/regs.h>
140b56e9a7SVivek Gautam #include <linux/gpio/consumer.h>
150b56e9a7SVivek Gautam #include <linux/phy/ulpi_phy.h>
1648969a56SStephan Gerhold #include <linux/power_supply.h>
177559e757SRob Herring #include <linux/property.h>
1848969a56SStephan Gerhold #include <linux/workqueue.h>
1948969a56SStephan Gerhold 
2048969a56SStephan Gerhold #define TUSB1211_POWER_CONTROL				0x3d
2148969a56SStephan Gerhold #define TUSB1211_POWER_CONTROL_SET			0x3e
2248969a56SStephan Gerhold #define TUSB1211_POWER_CONTROL_CLEAR			0x3f
2348969a56SStephan Gerhold #define TUSB1211_POWER_CONTROL_SW_CONTROL		BIT(0)
2448969a56SStephan Gerhold #define TUSB1211_POWER_CONTROL_DET_COMP			BIT(1)
2548969a56SStephan Gerhold #define TUSB1211_POWER_CONTROL_DP_VSRC_EN		BIT(6)
260b56e9a7SVivek Gautam 
270b56e9a7SVivek Gautam #define TUSB1210_VENDOR_SPECIFIC2			0x80
28eb445a15SLiam Beguin #define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK		GENMASK(3, 0)
29eb445a15SLiam Beguin #define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK		GENMASK(5, 4)
30eb445a15SLiam Beguin #define TUSB1210_VENDOR_SPECIFIC2_DP_MASK		BIT(6)
310b56e9a7SVivek Gautam 
3248969a56SStephan Gerhold #define TUSB1211_VENDOR_SPECIFIC3			0x85
3348969a56SStephan Gerhold #define TUSB1211_VENDOR_SPECIFIC3_SET			0x86
3448969a56SStephan Gerhold #define TUSB1211_VENDOR_SPECIFIC3_CLEAR			0x87
3548969a56SStephan Gerhold #define TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET		BIT(4)
3648969a56SStephan Gerhold #define TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN	BIT(6)
3748969a56SStephan Gerhold 
3848969a56SStephan Gerhold #define TUSB1210_RESET_TIME_MS				50
3948969a56SStephan Gerhold 
4048969a56SStephan Gerhold #define TUSB1210_CHG_DET_MAX_RETRIES			5
4148969a56SStephan Gerhold 
4248969a56SStephan Gerhold /* TUSB1210 charger detection work states */
4348969a56SStephan Gerhold enum tusb1210_chg_det_state {
4448969a56SStephan Gerhold 	TUSB1210_CHG_DET_CONNECTING,
4548969a56SStephan Gerhold 	TUSB1210_CHG_DET_START_DET,
4648969a56SStephan Gerhold 	TUSB1210_CHG_DET_READ_DET,
4748969a56SStephan Gerhold 	TUSB1210_CHG_DET_FINISH_DET,
4848969a56SStephan Gerhold 	TUSB1210_CHG_DET_CONNECTED,
4948969a56SStephan Gerhold 	TUSB1210_CHG_DET_DISCONNECTING,
5048969a56SStephan Gerhold 	TUSB1210_CHG_DET_DISCONNECTING_DONE,
5148969a56SStephan Gerhold 	TUSB1210_CHG_DET_DISCONNECTED,
5248969a56SStephan Gerhold };
53df37c998SHans de Goede 
540b56e9a7SVivek Gautam struct tusb1210 {
550b56e9a7SVivek Gautam 	struct ulpi *ulpi;
560b56e9a7SVivek Gautam 	struct phy *phy;
570b56e9a7SVivek Gautam 	struct gpio_desc *gpio_reset;
580b56e9a7SVivek Gautam 	struct gpio_desc *gpio_cs;
5948969a56SStephan Gerhold 	u8 otg_ctrl;
600b56e9a7SVivek Gautam 	u8 vendor_specific2;
6148969a56SStephan Gerhold #ifdef CONFIG_POWER_SUPPLY
6248969a56SStephan Gerhold 	enum power_supply_usb_type chg_type;
6348969a56SStephan Gerhold 	enum tusb1210_chg_det_state chg_det_state;
6448969a56SStephan Gerhold 	int chg_det_retries;
6548969a56SStephan Gerhold 	struct delayed_work chg_det_work;
6648969a56SStephan Gerhold 	struct notifier_block psy_nb;
6748969a56SStephan Gerhold 	struct power_supply *psy;
6848969a56SStephan Gerhold #endif
690b56e9a7SVivek Gautam };
700b56e9a7SVivek Gautam 
tusb1210_ulpi_write(struct tusb1210 * tusb,u8 reg,u8 val)7109a35126SHans de Goede static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
7209a35126SHans de Goede {
7309a35126SHans de Goede 	int ret;
7409a35126SHans de Goede 
7509a35126SHans de Goede 	ret = ulpi_write(tusb->ulpi, reg, val);
7609a35126SHans de Goede 	if (ret)
7709a35126SHans de Goede 		dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n",
7809a35126SHans de Goede 			ret, val, reg);
7909a35126SHans de Goede 
8009a35126SHans de Goede 	return ret;
8109a35126SHans de Goede }
8209a35126SHans de Goede 
tusb1210_ulpi_read(struct tusb1210 * tusb,u8 reg,u8 * val)8309a35126SHans de Goede static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val)
8409a35126SHans de Goede {
8509a35126SHans de Goede 	int ret;
8609a35126SHans de Goede 
8709a35126SHans de Goede 	ret = ulpi_read(tusb->ulpi, reg);
8809a35126SHans de Goede 	if (ret >= 0) {
8909a35126SHans de Goede 		*val = ret;
9009a35126SHans de Goede 		ret = 0;
9109a35126SHans de Goede 	} else {
9209a35126SHans de Goede 		dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg);
9309a35126SHans de Goede 	}
9409a35126SHans de Goede 
9509a35126SHans de Goede 	return ret;
9609a35126SHans de Goede }
9709a35126SHans de Goede 
tusb1210_power_on(struct phy * phy)980b56e9a7SVivek Gautam static int tusb1210_power_on(struct phy *phy)
990b56e9a7SVivek Gautam {
1000b56e9a7SVivek Gautam 	struct tusb1210 *tusb = phy_get_drvdata(phy);
1010b56e9a7SVivek Gautam 
1020b56e9a7SVivek Gautam 	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
1030b56e9a7SVivek Gautam 	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
1040b56e9a7SVivek Gautam 
105df37c998SHans de Goede 	msleep(TUSB1210_RESET_TIME_MS);
106df37c998SHans de Goede 
1070b56e9a7SVivek Gautam 	/* Restore the optional eye diagram optimization value */
108d4a0a189SAndy Shevchenko 	tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, tusb->vendor_specific2);
109d4a0a189SAndy Shevchenko 
110d4a0a189SAndy Shevchenko 	return 0;
1110b56e9a7SVivek Gautam }
1120b56e9a7SVivek Gautam 
tusb1210_power_off(struct phy * phy)1130b56e9a7SVivek Gautam static int tusb1210_power_off(struct phy *phy)
1140b56e9a7SVivek Gautam {
1150b56e9a7SVivek Gautam 	struct tusb1210 *tusb = phy_get_drvdata(phy);
1160b56e9a7SVivek Gautam 
1170b56e9a7SVivek Gautam 	gpiod_set_value_cansleep(tusb->gpio_reset, 0);
1180b56e9a7SVivek Gautam 	gpiod_set_value_cansleep(tusb->gpio_cs, 0);
1190b56e9a7SVivek Gautam 
1200b56e9a7SVivek Gautam 	return 0;
1210b56e9a7SVivek Gautam }
1220b56e9a7SVivek Gautam 
tusb1210_set_mode(struct phy * phy,enum phy_mode mode,int submode)12379a5a18aSGrygorii Strashko static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
12454fe3088SFelipe Balbi {
12554fe3088SFelipe Balbi 	struct tusb1210 *tusb = phy_get_drvdata(phy);
12654fe3088SFelipe Balbi 	int ret;
12709a35126SHans de Goede 	u8 reg;
12854fe3088SFelipe Balbi 
12909a35126SHans de Goede 	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &reg);
13054fe3088SFelipe Balbi 	if (ret < 0)
13154fe3088SFelipe Balbi 		return ret;
13254fe3088SFelipe Balbi 
13354fe3088SFelipe Balbi 	switch (mode) {
13454fe3088SFelipe Balbi 	case PHY_MODE_USB_HOST:
13509a35126SHans de Goede 		reg |= (ULPI_OTG_CTRL_DRVVBUS_EXT
13654fe3088SFelipe Balbi 			| ULPI_OTG_CTRL_ID_PULLUP
13754fe3088SFelipe Balbi 			| ULPI_OTG_CTRL_DP_PULLDOWN
13854fe3088SFelipe Balbi 			| ULPI_OTG_CTRL_DM_PULLDOWN);
13909a35126SHans de Goede 		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
14009a35126SHans de Goede 		reg |= ULPI_OTG_CTRL_DRVVBUS;
14154fe3088SFelipe Balbi 		break;
14254fe3088SFelipe Balbi 	case PHY_MODE_USB_DEVICE:
14309a35126SHans de Goede 		reg &= ~(ULPI_OTG_CTRL_DRVVBUS
14454fe3088SFelipe Balbi 			 | ULPI_OTG_CTRL_DP_PULLDOWN
14554fe3088SFelipe Balbi 			 | ULPI_OTG_CTRL_DM_PULLDOWN);
14609a35126SHans de Goede 		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
14709a35126SHans de Goede 		reg &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
14854fe3088SFelipe Balbi 		break;
14954fe3088SFelipe Balbi 	default:
15054fe3088SFelipe Balbi 		/* nothing */
15154fe3088SFelipe Balbi 		return 0;
15254fe3088SFelipe Balbi 	}
15354fe3088SFelipe Balbi 
15448969a56SStephan Gerhold 	tusb->otg_ctrl = reg;
15509a35126SHans de Goede 	return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
15654fe3088SFelipe Balbi }
15754fe3088SFelipe Balbi 
15848969a56SStephan Gerhold #ifdef CONFIG_POWER_SUPPLY
159b541f9e5SHans de Goede static const char * const tusb1210_chg_det_states[] = {
16048969a56SStephan Gerhold 	"CHG_DET_CONNECTING",
16148969a56SStephan Gerhold 	"CHG_DET_START_DET",
16248969a56SStephan Gerhold 	"CHG_DET_READ_DET",
16348969a56SStephan Gerhold 	"CHG_DET_FINISH_DET",
16448969a56SStephan Gerhold 	"CHG_DET_CONNECTED",
16548969a56SStephan Gerhold 	"CHG_DET_DISCONNECTING",
16648969a56SStephan Gerhold 	"CHG_DET_DISCONNECTING_DONE",
16748969a56SStephan Gerhold 	"CHG_DET_DISCONNECTED",
16848969a56SStephan Gerhold };
16948969a56SStephan Gerhold 
tusb1210_reset(struct tusb1210 * tusb)17048969a56SStephan Gerhold static void tusb1210_reset(struct tusb1210 *tusb)
17148969a56SStephan Gerhold {
17248969a56SStephan Gerhold 	gpiod_set_value_cansleep(tusb->gpio_reset, 0);
17348969a56SStephan Gerhold 	usleep_range(200, 500);
17448969a56SStephan Gerhold 	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
17548969a56SStephan Gerhold }
17648969a56SStephan Gerhold 
tusb1210_chg_det_set_type(struct tusb1210 * tusb,enum power_supply_usb_type type)17748969a56SStephan Gerhold static void tusb1210_chg_det_set_type(struct tusb1210 *tusb,
17848969a56SStephan Gerhold 				      enum power_supply_usb_type type)
17948969a56SStephan Gerhold {
18048969a56SStephan Gerhold 	dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type);
18148969a56SStephan Gerhold 	tusb->chg_type = type;
18248969a56SStephan Gerhold 	tusb->chg_det_retries = 0;
18348969a56SStephan Gerhold 	power_supply_changed(tusb->psy);
18448969a56SStephan Gerhold }
18548969a56SStephan Gerhold 
tusb1210_chg_det_set_state(struct tusb1210 * tusb,enum tusb1210_chg_det_state new_state,int delay_ms)18648969a56SStephan Gerhold static void tusb1210_chg_det_set_state(struct tusb1210 *tusb,
18748969a56SStephan Gerhold 				       enum tusb1210_chg_det_state new_state,
18848969a56SStephan Gerhold 				       int delay_ms)
18948969a56SStephan Gerhold {
19048969a56SStephan Gerhold 	if (delay_ms)
19148969a56SStephan Gerhold 		dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n",
19248969a56SStephan Gerhold 			tusb1210_chg_det_states[new_state], delay_ms);
19348969a56SStephan Gerhold 
19448969a56SStephan Gerhold 	tusb->chg_det_state = new_state;
19548969a56SStephan Gerhold 	mod_delayed_work(system_long_wq, &tusb->chg_det_work,
19648969a56SStephan Gerhold 			 msecs_to_jiffies(delay_ms));
19748969a56SStephan Gerhold }
19848969a56SStephan Gerhold 
tusb1210_chg_det_handle_ulpi_error(struct tusb1210 * tusb)19948969a56SStephan Gerhold static void tusb1210_chg_det_handle_ulpi_error(struct tusb1210 *tusb)
20048969a56SStephan Gerhold {
20148969a56SStephan Gerhold 	tusb1210_reset(tusb);
20248969a56SStephan Gerhold 	if (tusb->chg_det_retries < TUSB1210_CHG_DET_MAX_RETRIES) {
20348969a56SStephan Gerhold 		tusb->chg_det_retries++;
20448969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET,
20548969a56SStephan Gerhold 					   TUSB1210_RESET_TIME_MS);
20648969a56SStephan Gerhold 	} else {
20748969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET,
20848969a56SStephan Gerhold 					   TUSB1210_RESET_TIME_MS);
20948969a56SStephan Gerhold 	}
21048969a56SStephan Gerhold }
21148969a56SStephan Gerhold 
21248969a56SStephan Gerhold /*
21348969a56SStephan Gerhold  * Boards using a TUSB121x for charger-detection have 3 power_supply class devs:
21448969a56SStephan Gerhold  *
21548969a56SStephan Gerhold  * tusb1211-charger-detect(1) -> charger -> fuel-gauge
21648969a56SStephan Gerhold  *
21748969a56SStephan Gerhold  * To determine if an USB charger is connected to the board, the online prop of
21848969a56SStephan Gerhold  * the charger psy needs to be read. Since the tusb1211-charger-detect psy is
21948969a56SStephan Gerhold  * the start of the supplier -> supplied-to chain, power_supply_am_i_supplied()
22048969a56SStephan Gerhold  * cannot be used here.
22148969a56SStephan Gerhold  *
22248969a56SStephan Gerhold  * Instead, below is a list of the power_supply names of known chargers for
22348969a56SStephan Gerhold  * these boards and the charger psy is looked up by name from this list.
22448969a56SStephan Gerhold  *
22548969a56SStephan Gerhold  * (1) modelling the external USB charger
22648969a56SStephan Gerhold  */
22748969a56SStephan Gerhold static const char * const tusb1210_chargers[] = {
22848969a56SStephan Gerhold 	"bq24190-charger",
22948969a56SStephan Gerhold };
23048969a56SStephan Gerhold 
tusb1210_get_online(struct tusb1210 * tusb)23148969a56SStephan Gerhold static bool tusb1210_get_online(struct tusb1210 *tusb)
23248969a56SStephan Gerhold {
23373224a5dSHans de Goede 	struct power_supply *charger = NULL;
23448969a56SStephan Gerhold 	union power_supply_propval val;
23573224a5dSHans de Goede 	bool online = false;
23673224a5dSHans de Goede 	int i, ret;
23748969a56SStephan Gerhold 
23873224a5dSHans de Goede 	for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !charger; i++)
23973224a5dSHans de Goede 		charger = power_supply_get_by_name(tusb1210_chargers[i]);
24048969a56SStephan Gerhold 
24173224a5dSHans de Goede 	if (!charger)
24248969a56SStephan Gerhold 		return false;
24348969a56SStephan Gerhold 
24473224a5dSHans de Goede 	ret = power_supply_get_property(charger, POWER_SUPPLY_PROP_ONLINE, &val);
24573224a5dSHans de Goede 	if (ret == 0)
24673224a5dSHans de Goede 		online = val.intval;
24748969a56SStephan Gerhold 
24873224a5dSHans de Goede 	power_supply_put(charger);
24973224a5dSHans de Goede 
25073224a5dSHans de Goede 	return online;
25148969a56SStephan Gerhold }
25248969a56SStephan Gerhold 
tusb1210_chg_det_work(struct work_struct * work)25348969a56SStephan Gerhold static void tusb1210_chg_det_work(struct work_struct *work)
25448969a56SStephan Gerhold {
25548969a56SStephan Gerhold 	struct tusb1210 *tusb = container_of(work, struct tusb1210, chg_det_work.work);
25648969a56SStephan Gerhold 	bool vbus_present = tusb1210_get_online(tusb);
25748969a56SStephan Gerhold 	int ret;
25848969a56SStephan Gerhold 	u8 val;
25948969a56SStephan Gerhold 
26048969a56SStephan Gerhold 	dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n",
26148969a56SStephan Gerhold 		tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
26248969a56SStephan Gerhold 
26348969a56SStephan Gerhold 	switch (tusb->chg_det_state) {
26448969a56SStephan Gerhold 	case TUSB1210_CHG_DET_CONNECTING:
26548969a56SStephan Gerhold 		tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
26648969a56SStephan Gerhold 		tusb->chg_det_retries = 0;
26748969a56SStephan Gerhold 		/* Power on USB controller for ulpi_read()/_write() */
26848969a56SStephan Gerhold 		ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent);
26948969a56SStephan Gerhold 		if (ret < 0) {
27048969a56SStephan Gerhold 			dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret);
27148969a56SStephan Gerhold 			/* Should never happen, skip charger detection */
27248969a56SStephan Gerhold 			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
27348969a56SStephan Gerhold 			return;
27448969a56SStephan Gerhold 		}
27548969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0);
27648969a56SStephan Gerhold 		break;
27748969a56SStephan Gerhold 	case TUSB1210_CHG_DET_START_DET:
27848969a56SStephan Gerhold 		/*
27948969a56SStephan Gerhold 		 * Use the builtin charger detection FSM to keep things simple.
28048969a56SStephan Gerhold 		 * This only detects DCP / SDP. This is good enough for the few
28148969a56SStephan Gerhold 		 * boards which actually rely on the phy for charger detection.
28248969a56SStephan Gerhold 		 */
28348969a56SStephan Gerhold 		mutex_lock(&tusb->phy->mutex);
28448969a56SStephan Gerhold 		ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
28548969a56SStephan Gerhold 					  TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
28648969a56SStephan Gerhold 		mutex_unlock(&tusb->phy->mutex);
28748969a56SStephan Gerhold 		if (ret) {
28848969a56SStephan Gerhold 			tusb1210_chg_det_handle_ulpi_error(tusb);
28948969a56SStephan Gerhold 			break;
29048969a56SStephan Gerhold 		}
29148969a56SStephan Gerhold 
29248969a56SStephan Gerhold 		/* Wait 400 ms for the charger detection FSM to finish */
29348969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400);
29448969a56SStephan Gerhold 		break;
29548969a56SStephan Gerhold 	case TUSB1210_CHG_DET_READ_DET:
29648969a56SStephan Gerhold 		mutex_lock(&tusb->phy->mutex);
29748969a56SStephan Gerhold 		ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
29848969a56SStephan Gerhold 		mutex_unlock(&tusb->phy->mutex);
29948969a56SStephan Gerhold 		if (ret) {
30048969a56SStephan Gerhold 			tusb1210_chg_det_handle_ulpi_error(tusb);
30148969a56SStephan Gerhold 			break;
30248969a56SStephan Gerhold 		}
30348969a56SStephan Gerhold 
30448969a56SStephan Gerhold 		if (val & TUSB1211_POWER_CONTROL_DET_COMP)
30548969a56SStephan Gerhold 			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP);
30648969a56SStephan Gerhold 		else
30748969a56SStephan Gerhold 			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
30848969a56SStephan Gerhold 
30948969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0);
31048969a56SStephan Gerhold 		break;
31148969a56SStephan Gerhold 	case TUSB1210_CHG_DET_FINISH_DET:
31248969a56SStephan Gerhold 		mutex_lock(&tusb->phy->mutex);
31348969a56SStephan Gerhold 
31448969a56SStephan Gerhold 		/* Set SW_CONTROL to stop the charger-det FSM */
31548969a56SStephan Gerhold 		ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
31648969a56SStephan Gerhold 					  TUSB1211_POWER_CONTROL_SW_CONTROL);
31748969a56SStephan Gerhold 
31848969a56SStephan Gerhold 		/* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
31948969a56SStephan Gerhold 		ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
32048969a56SStephan Gerhold 					   TUSB1211_POWER_CONTROL_DP_VSRC_EN);
32148969a56SStephan Gerhold 
32248969a56SStephan Gerhold 		/* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
32348969a56SStephan Gerhold 		ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
32448969a56SStephan Gerhold 					   TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
32548969a56SStephan Gerhold 
32648969a56SStephan Gerhold 		/* If any of the above fails reset the phy */
32748969a56SStephan Gerhold 		if (ret) {
32848969a56SStephan Gerhold 			tusb1210_reset(tusb);
32948969a56SStephan Gerhold 			msleep(TUSB1210_RESET_TIME_MS);
33048969a56SStephan Gerhold 		}
33148969a56SStephan Gerhold 
33248969a56SStephan Gerhold 		/* Restore phy-parameters and OTG_CTRL register */
33348969a56SStephan Gerhold 		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, tusb->otg_ctrl);
33448969a56SStephan Gerhold 		tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
33548969a56SStephan Gerhold 				    tusb->vendor_specific2);
33648969a56SStephan Gerhold 
33748969a56SStephan Gerhold 		mutex_unlock(&tusb->phy->mutex);
33848969a56SStephan Gerhold 
33948969a56SStephan Gerhold 		pm_runtime_put(tusb->ulpi->dev.parent);
34048969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
34148969a56SStephan Gerhold 		break;
34248969a56SStephan Gerhold 	case TUSB1210_CHG_DET_CONNECTED:
34348969a56SStephan Gerhold 		if (!vbus_present)
34448969a56SStephan Gerhold 			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0);
34548969a56SStephan Gerhold 		break;
34648969a56SStephan Gerhold 	case TUSB1210_CHG_DET_DISCONNECTING:
34748969a56SStephan Gerhold 		/*
34848969a56SStephan Gerhold 		 * The phy seems to take approx. 600ms longer then the charger
34948969a56SStephan Gerhold 		 * chip (which is used to get vbus_present) to determine Vbus
35048969a56SStephan Gerhold 		 * session end. Wait 800ms to ensure the phy has detected and
35148969a56SStephan Gerhold 		 * signalled Vbus session end.
35248969a56SStephan Gerhold 		 */
35348969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800);
35448969a56SStephan Gerhold 		break;
35548969a56SStephan Gerhold 	case TUSB1210_CHG_DET_DISCONNECTING_DONE:
35648969a56SStephan Gerhold 		/*
35748969a56SStephan Gerhold 		 * The phy often stops reacting to ulpi_read()/_write requests
35848969a56SStephan Gerhold 		 * after a Vbus-session end. Reset it to work around this.
35948969a56SStephan Gerhold 		 */
36048969a56SStephan Gerhold 		tusb1210_reset(tusb);
36148969a56SStephan Gerhold 		tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
36248969a56SStephan Gerhold 		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0);
36348969a56SStephan Gerhold 		break;
36448969a56SStephan Gerhold 	case TUSB1210_CHG_DET_DISCONNECTED:
36548969a56SStephan Gerhold 		if (vbus_present)
36648969a56SStephan Gerhold 			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0);
36748969a56SStephan Gerhold 		break;
36848969a56SStephan Gerhold 	}
36948969a56SStephan Gerhold }
37048969a56SStephan Gerhold 
tusb1210_psy_notifier(struct notifier_block * nb,unsigned long event,void * ptr)37148969a56SStephan Gerhold static int tusb1210_psy_notifier(struct notifier_block *nb,
37248969a56SStephan Gerhold 	unsigned long event, void *ptr)
37348969a56SStephan Gerhold {
37448969a56SStephan Gerhold 	struct tusb1210 *tusb = container_of(nb, struct tusb1210, psy_nb);
37548969a56SStephan Gerhold 	struct power_supply *psy = ptr;
37648969a56SStephan Gerhold 
37748969a56SStephan Gerhold 	if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB)
37848969a56SStephan Gerhold 		queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0);
37948969a56SStephan Gerhold 
38048969a56SStephan Gerhold 	return NOTIFY_OK;
38148969a56SStephan Gerhold }
38248969a56SStephan Gerhold 
tusb1210_psy_get_prop(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)38348969a56SStephan Gerhold static int tusb1210_psy_get_prop(struct power_supply *psy,
38448969a56SStephan Gerhold 				 enum power_supply_property psp,
38548969a56SStephan Gerhold 				 union power_supply_propval *val)
38648969a56SStephan Gerhold {
38748969a56SStephan Gerhold 	struct tusb1210 *tusb = power_supply_get_drvdata(psy);
38848969a56SStephan Gerhold 
38948969a56SStephan Gerhold 	switch (psp) {
39048969a56SStephan Gerhold 	case POWER_SUPPLY_PROP_ONLINE:
39148969a56SStephan Gerhold 		val->intval = tusb1210_get_online(tusb);
39248969a56SStephan Gerhold 		break;
39348969a56SStephan Gerhold 	case POWER_SUPPLY_PROP_USB_TYPE:
39448969a56SStephan Gerhold 		val->intval = tusb->chg_type;
39548969a56SStephan Gerhold 		break;
39648969a56SStephan Gerhold 	case POWER_SUPPLY_PROP_CURRENT_MAX:
39748969a56SStephan Gerhold 		if (tusb->chg_type == POWER_SUPPLY_USB_TYPE_DCP)
39848969a56SStephan Gerhold 			val->intval = 2000000;
39948969a56SStephan Gerhold 		else
40048969a56SStephan Gerhold 			val->intval = 500000;
40148969a56SStephan Gerhold 		break;
40248969a56SStephan Gerhold 	default:
40348969a56SStephan Gerhold 		return -EINVAL;
40448969a56SStephan Gerhold 	}
40548969a56SStephan Gerhold 
40648969a56SStephan Gerhold 	return 0;
40748969a56SStephan Gerhold }
40848969a56SStephan Gerhold 
40948969a56SStephan Gerhold static const enum power_supply_usb_type tusb1210_psy_usb_types[] = {
41048969a56SStephan Gerhold 	POWER_SUPPLY_USB_TYPE_SDP,
41148969a56SStephan Gerhold 	POWER_SUPPLY_USB_TYPE_DCP,
41248969a56SStephan Gerhold 	POWER_SUPPLY_USB_TYPE_UNKNOWN,
41348969a56SStephan Gerhold };
41448969a56SStephan Gerhold 
41548969a56SStephan Gerhold static const enum power_supply_property tusb1210_psy_props[] = {
41648969a56SStephan Gerhold 	POWER_SUPPLY_PROP_ONLINE,
41748969a56SStephan Gerhold 	POWER_SUPPLY_PROP_USB_TYPE,
41848969a56SStephan Gerhold 	POWER_SUPPLY_PROP_CURRENT_MAX,
41948969a56SStephan Gerhold };
42048969a56SStephan Gerhold 
42148969a56SStephan Gerhold static const struct power_supply_desc tusb1210_psy_desc = {
42248969a56SStephan Gerhold 	.name = "tusb1211-charger-detect",
42348969a56SStephan Gerhold 	.type = POWER_SUPPLY_TYPE_USB,
42448969a56SStephan Gerhold 	.usb_types = tusb1210_psy_usb_types,
42548969a56SStephan Gerhold 	.num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types),
42648969a56SStephan Gerhold 	.properties = tusb1210_psy_props,
42748969a56SStephan Gerhold 	.num_properties = ARRAY_SIZE(tusb1210_psy_props),
42848969a56SStephan Gerhold 	.get_property = tusb1210_psy_get_prop,
42948969a56SStephan Gerhold };
43048969a56SStephan Gerhold 
43148969a56SStephan Gerhold /* Setup charger detection if requested, on errors continue without chg-det */
tusb1210_probe_charger_detect(struct tusb1210 * tusb)43248969a56SStephan Gerhold static void tusb1210_probe_charger_detect(struct tusb1210 *tusb)
43348969a56SStephan Gerhold {
43448969a56SStephan Gerhold 	struct power_supply_config psy_cfg = { .drv_data = tusb };
43548969a56SStephan Gerhold 	struct device *dev = &tusb->ulpi->dev;
43648969a56SStephan Gerhold 	int ret;
43748969a56SStephan Gerhold 
43848969a56SStephan Gerhold 	if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect"))
43948969a56SStephan Gerhold 		return;
44048969a56SStephan Gerhold 
44148969a56SStephan Gerhold 	if (tusb->ulpi->id.product != 0x1508) {
44248969a56SStephan Gerhold 		dev_err(dev, "error charger detection is only supported on the TUSB1211\n");
44348969a56SStephan Gerhold 		return;
44448969a56SStephan Gerhold 	}
44548969a56SStephan Gerhold 
44648969a56SStephan Gerhold 	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl);
44748969a56SStephan Gerhold 	if (ret)
44848969a56SStephan Gerhold 		return;
44948969a56SStephan Gerhold 
45048969a56SStephan Gerhold 	tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg);
45148969a56SStephan Gerhold 	if (IS_ERR(tusb->psy))
45248969a56SStephan Gerhold 		return;
45348969a56SStephan Gerhold 
45448969a56SStephan Gerhold 	/*
45548969a56SStephan Gerhold 	 * Delay initial run by 2 seconds to allow the charger driver,
45648969a56SStephan Gerhold 	 * which is used to determine vbus_present, to load.
45748969a56SStephan Gerhold 	 */
45848969a56SStephan Gerhold 	tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
45948969a56SStephan Gerhold 	INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
46048969a56SStephan Gerhold 	queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
46148969a56SStephan Gerhold 
46248969a56SStephan Gerhold 	tusb->psy_nb.notifier_call = tusb1210_psy_notifier;
46348969a56SStephan Gerhold 	power_supply_reg_notifier(&tusb->psy_nb);
46448969a56SStephan Gerhold }
46548969a56SStephan Gerhold 
tusb1210_remove_charger_detect(struct tusb1210 * tusb)46648969a56SStephan Gerhold static void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
46748969a56SStephan Gerhold {
46848969a56SStephan Gerhold 
46948969a56SStephan Gerhold 	if (!IS_ERR_OR_NULL(tusb->psy)) {
47048969a56SStephan Gerhold 		power_supply_unreg_notifier(&tusb->psy_nb);
47148969a56SStephan Gerhold 		cancel_delayed_work_sync(&tusb->chg_det_work);
47248969a56SStephan Gerhold 		power_supply_unregister(tusb->psy);
47348969a56SStephan Gerhold 	}
47448969a56SStephan Gerhold }
47548969a56SStephan Gerhold #else
tusb1210_probe_charger_detect(struct tusb1210 * tusb)47648969a56SStephan Gerhold static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }
tusb1210_remove_charger_detect(struct tusb1210 * tusb)47748969a56SStephan Gerhold static void tusb1210_remove_charger_detect(struct tusb1210 *tusb) { }
47848969a56SStephan Gerhold #endif
47948969a56SStephan Gerhold 
4800b56e9a7SVivek Gautam static const struct phy_ops phy_ops = {
4810b56e9a7SVivek Gautam 	.power_on = tusb1210_power_on,
4820b56e9a7SVivek Gautam 	.power_off = tusb1210_power_off,
48354fe3088SFelipe Balbi 	.set_mode = tusb1210_set_mode,
4840b56e9a7SVivek Gautam 	.owner = THIS_MODULE,
4850b56e9a7SVivek Gautam };
4860b56e9a7SVivek Gautam 
tusb1210_probe(struct ulpi * ulpi)4870b56e9a7SVivek Gautam static int tusb1210_probe(struct ulpi *ulpi)
4880b56e9a7SVivek Gautam {
4890b56e9a7SVivek Gautam 	struct tusb1210 *tusb;
4900b56e9a7SVivek Gautam 	u8 val, reg;
49109a35126SHans de Goede 	int ret;
4920b56e9a7SVivek Gautam 
4930b56e9a7SVivek Gautam 	tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
4940b56e9a7SVivek Gautam 	if (!tusb)
4950b56e9a7SVivek Gautam 		return -ENOMEM;
4960b56e9a7SVivek Gautam 
49709a35126SHans de Goede 	tusb->ulpi = ulpi;
49809a35126SHans de Goede 
4990b56e9a7SVivek Gautam 	tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
5000b56e9a7SVivek Gautam 						   GPIOD_OUT_LOW);
5010b56e9a7SVivek Gautam 	if (IS_ERR(tusb->gpio_reset))
5020b56e9a7SVivek Gautam 		return PTR_ERR(tusb->gpio_reset);
5030b56e9a7SVivek Gautam 
5040b56e9a7SVivek Gautam 	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
5050b56e9a7SVivek Gautam 
5060b56e9a7SVivek Gautam 	tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs",
5070b56e9a7SVivek Gautam 						GPIOD_OUT_LOW);
5080b56e9a7SVivek Gautam 	if (IS_ERR(tusb->gpio_cs))
5090b56e9a7SVivek Gautam 		return PTR_ERR(tusb->gpio_cs);
5100b56e9a7SVivek Gautam 
5110b56e9a7SVivek Gautam 	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
5120b56e9a7SVivek Gautam 
5130b56e9a7SVivek Gautam 	/*
5140b56e9a7SVivek Gautam 	 * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
5150b56e9a7SVivek Gautam 	 * diagram optimization and DP/DM swap.
5160b56e9a7SVivek Gautam 	 */
5170b56e9a7SVivek Gautam 
51809a35126SHans de Goede 	ret = tusb1210_ulpi_read(tusb, TUSB1210_VENDOR_SPECIFIC2, &reg);
51909a35126SHans de Goede 	if (ret)
52009a35126SHans de Goede 		return ret;
521eb445a15SLiam Beguin 
5220b56e9a7SVivek Gautam 	/* High speed output drive strength configuration */
523eb445a15SLiam Beguin 	if (!device_property_read_u8(&ulpi->dev, "ihstx", &val))
524eb445a15SLiam Beguin 		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK);
5250b56e9a7SVivek Gautam 
5260b56e9a7SVivek Gautam 	/* High speed output impedance configuration */
527eb445a15SLiam Beguin 	if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val))
528eb445a15SLiam Beguin 		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK);
5290b56e9a7SVivek Gautam 
5300b56e9a7SVivek Gautam 	/* DP/DM swap control */
531eb445a15SLiam Beguin 	if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val))
532eb445a15SLiam Beguin 		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
5330b56e9a7SVivek Gautam 
53409a35126SHans de Goede 	ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg);
53509a35126SHans de Goede 	if (ret)
53609a35126SHans de Goede 		return ret;
53709a35126SHans de Goede 
5380b56e9a7SVivek Gautam 	tusb->vendor_specific2 = reg;
5390b56e9a7SVivek Gautam 
54048969a56SStephan Gerhold 	tusb1210_probe_charger_detect(tusb);
54148969a56SStephan Gerhold 
5420b56e9a7SVivek Gautam 	tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
543a9f17d0cSChristophe JAILLET 	if (IS_ERR(tusb->phy)) {
544a9f17d0cSChristophe JAILLET 		ret = PTR_ERR(tusb->phy);
545a9f17d0cSChristophe JAILLET 		goto err_remove_charger;
546a9f17d0cSChristophe JAILLET 	}
5470b56e9a7SVivek Gautam 
5480b56e9a7SVivek Gautam 	phy_set_drvdata(tusb->phy, tusb);
5490b56e9a7SVivek Gautam 	ulpi_set_drvdata(ulpi, tusb);
5500b56e9a7SVivek Gautam 	return 0;
551a9f17d0cSChristophe JAILLET 
552a9f17d0cSChristophe JAILLET err_remove_charger:
553a9f17d0cSChristophe JAILLET 	tusb1210_remove_charger_detect(tusb);
554a9f17d0cSChristophe JAILLET 	return ret;
5550b56e9a7SVivek Gautam }
5560b56e9a7SVivek Gautam 
tusb1210_remove(struct ulpi * ulpi)5570b56e9a7SVivek Gautam static void tusb1210_remove(struct ulpi *ulpi)
5580b56e9a7SVivek Gautam {
5590b56e9a7SVivek Gautam 	struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
5600b56e9a7SVivek Gautam 
5610b56e9a7SVivek Gautam 	ulpi_phy_destroy(ulpi, tusb->phy);
56248969a56SStephan Gerhold 	tusb1210_remove_charger_detect(tusb);
5630b56e9a7SVivek Gautam }
5640b56e9a7SVivek Gautam 
5650b56e9a7SVivek Gautam #define TI_VENDOR_ID 0x0451
5660b56e9a7SVivek Gautam 
5670b56e9a7SVivek Gautam static const struct ulpi_device_id tusb1210_ulpi_id[] = {
56882d9d5e0SFelipe Balbi 	{ TI_VENDOR_ID, 0x1507, },  /* TUSB1210 */
56982d9d5e0SFelipe Balbi 	{ TI_VENDOR_ID, 0x1508, },  /* TUSB1211 */
5700b56e9a7SVivek Gautam 	{ },
5710b56e9a7SVivek Gautam };
5720b56e9a7SVivek Gautam MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
5730b56e9a7SVivek Gautam 
5740b56e9a7SVivek Gautam static struct ulpi_driver tusb1210_driver = {
5750b56e9a7SVivek Gautam 	.id_table = tusb1210_ulpi_id,
5760b56e9a7SVivek Gautam 	.probe = tusb1210_probe,
5770b56e9a7SVivek Gautam 	.remove = tusb1210_remove,
5780b56e9a7SVivek Gautam 	.driver = {
5790b56e9a7SVivek Gautam 		.name = "tusb1210",
5800b56e9a7SVivek Gautam 		.owner = THIS_MODULE,
5810b56e9a7SVivek Gautam 	},
5820b56e9a7SVivek Gautam };
5830b56e9a7SVivek Gautam 
5840b56e9a7SVivek Gautam module_ulpi_driver(tusb1210_driver);
5850b56e9a7SVivek Gautam 
5860b56e9a7SVivek Gautam MODULE_AUTHOR("Intel Corporation");
5870b56e9a7SVivek Gautam MODULE_LICENSE("GPL v2");
5880b56e9a7SVivek Gautam MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
589