162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * USB transceiver driver for AB8500 family chips
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010-2013 ST-Ericsson AB
662306a36Sopenharmony_ci * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
762306a36Sopenharmony_ci * Avinash Kumar <avinash.kumar@stericsson.com>
862306a36Sopenharmony_ci * Thirupathi Chippakurthy <thirupathi.chippakurthy@stericsson.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/usb/otg.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/notifier.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/clk.h>
1962306a36Sopenharmony_ci#include <linux/err.h>
2062306a36Sopenharmony_ci#include <linux/mfd/abx500.h>
2162306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h>
2262306a36Sopenharmony_ci#include <linux/usb/musb-ux500.h>
2362306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
2462306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* Bank AB8500_SYS_CTRL2_BLOCK */
2762306a36Sopenharmony_ci#define AB8500_MAIN_WD_CTRL_REG 0x01
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* Bank AB8500_USB */
3062306a36Sopenharmony_ci#define AB8500_USB_LINE_STAT_REG 0x80
3162306a36Sopenharmony_ci#define AB8505_USB_LINE_STAT_REG 0x94
3262306a36Sopenharmony_ci#define AB8500_USB_PHY_CTRL_REG 0x8A
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Bank AB8500_DEVELOPMENT */
3562306a36Sopenharmony_ci#define AB8500_BANK12_ACCESS 0x00
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* Bank AB8500_DEBUG */
3862306a36Sopenharmony_ci#define AB8500_USB_PHY_TUNE1 0x05
3962306a36Sopenharmony_ci#define AB8500_USB_PHY_TUNE2 0x06
4062306a36Sopenharmony_ci#define AB8500_USB_PHY_TUNE3 0x07
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* Bank AB8500_INTERRUPT */
4362306a36Sopenharmony_ci#define AB8500_IT_SOURCE2_REG 0x01
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define AB8500_BIT_OTG_STAT_ID (1 << 0)
4662306a36Sopenharmony_ci#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
4762306a36Sopenharmony_ci#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
4862306a36Sopenharmony_ci#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
4962306a36Sopenharmony_ci#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
5062306a36Sopenharmony_ci#define AB8500_BIT_SOURCE2_VBUSDET (1 << 7)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define AB8500_WD_KICK_DELAY_US 100 /* usec */
5362306a36Sopenharmony_ci#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
5462306a36Sopenharmony_ci#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Usb line status register */
5762306a36Sopenharmony_cienum ab8500_usb_link_status {
5862306a36Sopenharmony_ci	USB_LINK_NOT_CONFIGURED_8500 = 0,
5962306a36Sopenharmony_ci	USB_LINK_STD_HOST_NC_8500,
6062306a36Sopenharmony_ci	USB_LINK_STD_HOST_C_NS_8500,
6162306a36Sopenharmony_ci	USB_LINK_STD_HOST_C_S_8500,
6262306a36Sopenharmony_ci	USB_LINK_HOST_CHG_NM_8500,
6362306a36Sopenharmony_ci	USB_LINK_HOST_CHG_HS_8500,
6462306a36Sopenharmony_ci	USB_LINK_HOST_CHG_HS_CHIRP_8500,
6562306a36Sopenharmony_ci	USB_LINK_DEDICATED_CHG_8500,
6662306a36Sopenharmony_ci	USB_LINK_ACA_RID_A_8500,
6762306a36Sopenharmony_ci	USB_LINK_ACA_RID_B_8500,
6862306a36Sopenharmony_ci	USB_LINK_ACA_RID_C_NM_8500,
6962306a36Sopenharmony_ci	USB_LINK_ACA_RID_C_HS_8500,
7062306a36Sopenharmony_ci	USB_LINK_ACA_RID_C_HS_CHIRP_8500,
7162306a36Sopenharmony_ci	USB_LINK_HM_IDGND_8500,
7262306a36Sopenharmony_ci	USB_LINK_RESERVED_8500,
7362306a36Sopenharmony_ci	USB_LINK_NOT_VALID_LINK_8500,
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cienum ab8505_usb_link_status {
7762306a36Sopenharmony_ci	USB_LINK_NOT_CONFIGURED_8505 = 0,
7862306a36Sopenharmony_ci	USB_LINK_STD_HOST_NC_8505,
7962306a36Sopenharmony_ci	USB_LINK_STD_HOST_C_NS_8505,
8062306a36Sopenharmony_ci	USB_LINK_STD_HOST_C_S_8505,
8162306a36Sopenharmony_ci	USB_LINK_CDP_8505,
8262306a36Sopenharmony_ci	USB_LINK_RESERVED0_8505,
8362306a36Sopenharmony_ci	USB_LINK_RESERVED1_8505,
8462306a36Sopenharmony_ci	USB_LINK_DEDICATED_CHG_8505,
8562306a36Sopenharmony_ci	USB_LINK_ACA_RID_A_8505,
8662306a36Sopenharmony_ci	USB_LINK_ACA_RID_B_8505,
8762306a36Sopenharmony_ci	USB_LINK_ACA_RID_C_NM_8505,
8862306a36Sopenharmony_ci	USB_LINK_RESERVED2_8505,
8962306a36Sopenharmony_ci	USB_LINK_RESERVED3_8505,
9062306a36Sopenharmony_ci	USB_LINK_HM_IDGND_8505,
9162306a36Sopenharmony_ci	USB_LINK_CHARGERPORT_NOT_OK_8505,
9262306a36Sopenharmony_ci	USB_LINK_CHARGER_DM_HIGH_8505,
9362306a36Sopenharmony_ci	USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505,
9462306a36Sopenharmony_ci	USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505,
9562306a36Sopenharmony_ci	USB_LINK_STD_UPSTREAM_8505,
9662306a36Sopenharmony_ci	USB_LINK_CHARGER_SE1_8505,
9762306a36Sopenharmony_ci	USB_LINK_CARKIT_CHGR_1_8505,
9862306a36Sopenharmony_ci	USB_LINK_CARKIT_CHGR_2_8505,
9962306a36Sopenharmony_ci	USB_LINK_ACA_DOCK_CHGR_8505,
10062306a36Sopenharmony_ci	USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505,
10162306a36Sopenharmony_ci	USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505,
10262306a36Sopenharmony_ci	USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505,
10362306a36Sopenharmony_ci	USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505,
10462306a36Sopenharmony_ci	USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cienum ab8500_usb_mode {
10862306a36Sopenharmony_ci	USB_IDLE = 0,
10962306a36Sopenharmony_ci	USB_PERIPHERAL,
11062306a36Sopenharmony_ci	USB_HOST,
11162306a36Sopenharmony_ci	USB_DEDICATED_CHG,
11262306a36Sopenharmony_ci	USB_UART
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Register USB_LINK_STATUS interrupt */
11662306a36Sopenharmony_ci#define AB8500_USB_FLAG_USE_LINK_STATUS_IRQ	(1 << 0)
11762306a36Sopenharmony_ci/* Register ID_WAKEUP_F interrupt */
11862306a36Sopenharmony_ci#define AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ	(1 << 1)
11962306a36Sopenharmony_ci/* Register VBUS_DET_F interrupt */
12062306a36Sopenharmony_ci#define AB8500_USB_FLAG_USE_VBUS_DET_IRQ	(1 << 2)
12162306a36Sopenharmony_ci/* Driver is using the ab-iddet driver*/
12262306a36Sopenharmony_ci#define AB8500_USB_FLAG_USE_AB_IDDET		(1 << 3)
12362306a36Sopenharmony_ci/* Enable setting regulators voltage */
12462306a36Sopenharmony_ci#define AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE	(1 << 4)
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistruct ab8500_usb {
12762306a36Sopenharmony_ci	struct usb_phy phy;
12862306a36Sopenharmony_ci	struct device *dev;
12962306a36Sopenharmony_ci	struct ab8500 *ab8500;
13062306a36Sopenharmony_ci	unsigned vbus_draw;
13162306a36Sopenharmony_ci	struct work_struct phy_dis_work;
13262306a36Sopenharmony_ci	enum ab8500_usb_mode mode;
13362306a36Sopenharmony_ci	struct clk *sysclk;
13462306a36Sopenharmony_ci	struct regulator *v_ape;
13562306a36Sopenharmony_ci	struct regulator *v_musb;
13662306a36Sopenharmony_ci	struct regulator *v_ulpi;
13762306a36Sopenharmony_ci	int saved_v_ulpi;
13862306a36Sopenharmony_ci	int previous_link_status_state;
13962306a36Sopenharmony_ci	struct pinctrl *pinctrl;
14062306a36Sopenharmony_ci	struct pinctrl_state *pins_sleep;
14162306a36Sopenharmony_ci	bool enabled_charging_detection;
14262306a36Sopenharmony_ci	unsigned int flags;
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	return container_of(x, struct ab8500_usb, phy);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	abx500_set_register_interruptible(ab->dev,
15362306a36Sopenharmony_ci		AB8500_SYS_CTRL2_BLOCK,
15462306a36Sopenharmony_ci		AB8500_MAIN_WD_CTRL_REG,
15562306a36Sopenharmony_ci		AB8500_BIT_WD_CTRL_ENABLE);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	udelay(AB8500_WD_KICK_DELAY_US);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	abx500_set_register_interruptible(ab->dev,
16062306a36Sopenharmony_ci		AB8500_SYS_CTRL2_BLOCK,
16162306a36Sopenharmony_ci		AB8500_MAIN_WD_CTRL_REG,
16262306a36Sopenharmony_ci		(AB8500_BIT_WD_CTRL_ENABLE
16362306a36Sopenharmony_ci		| AB8500_BIT_WD_CTRL_KICK));
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	udelay(AB8500_WD_V11_DISABLE_DELAY_US);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	abx500_set_register_interruptible(ab->dev,
16862306a36Sopenharmony_ci		AB8500_SYS_CTRL2_BLOCK,
16962306a36Sopenharmony_ci		AB8500_MAIN_WD_CTRL_REG,
17062306a36Sopenharmony_ci		0);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic void ab8500_usb_regulator_enable(struct ab8500_usb *ab)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	int ret, volt;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	ret = regulator_enable(ab->v_ape);
17862306a36Sopenharmony_ci	if (ret)
17962306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to enable v-ape\n");
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (ab->flags & AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE) {
18262306a36Sopenharmony_ci		ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi);
18362306a36Sopenharmony_ci		if (ab->saved_v_ulpi < 0)
18462306a36Sopenharmony_ci			dev_err(ab->dev, "Failed to get v_ulpi voltage\n");
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000);
18762306a36Sopenharmony_ci		if (ret < 0)
18862306a36Sopenharmony_ci			dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n",
18962306a36Sopenharmony_ci					ret);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		ret = regulator_set_load(ab->v_ulpi, 28000);
19262306a36Sopenharmony_ci		if (ret < 0)
19362306a36Sopenharmony_ci			dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
19462306a36Sopenharmony_ci					ret);
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	ret = regulator_enable(ab->v_ulpi);
19862306a36Sopenharmony_ci	if (ret)
19962306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to enable vddulpivio18\n");
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (ab->flags & AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE) {
20262306a36Sopenharmony_ci		volt = regulator_get_voltage(ab->v_ulpi);
20362306a36Sopenharmony_ci		if ((volt != 1300000) && (volt != 1350000))
20462306a36Sopenharmony_ci			dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n",
20562306a36Sopenharmony_ci					volt);
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	ret = regulator_enable(ab->v_musb);
20962306a36Sopenharmony_ci	if (ret)
21062306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to enable musb_1v8\n");
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic void ab8500_usb_regulator_disable(struct ab8500_usb *ab)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	int ret;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	regulator_disable(ab->v_musb);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	regulator_disable(ab->v_ulpi);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* USB is not the only consumer of Vintcore, restore old settings */
22262306a36Sopenharmony_ci	if (ab->flags & AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE) {
22362306a36Sopenharmony_ci		if (ab->saved_v_ulpi > 0) {
22462306a36Sopenharmony_ci			ret = regulator_set_voltage(ab->v_ulpi,
22562306a36Sopenharmony_ci					ab->saved_v_ulpi, ab->saved_v_ulpi);
22662306a36Sopenharmony_ci			if (ret < 0)
22762306a36Sopenharmony_ci				dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n",
22862306a36Sopenharmony_ci						ab->saved_v_ulpi, ret);
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		ret = regulator_set_load(ab->v_ulpi, 0);
23262306a36Sopenharmony_ci		if (ret < 0)
23362306a36Sopenharmony_ci			dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
23462306a36Sopenharmony_ci					ret);
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	regulator_disable(ab->v_ape);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	/* Workaround for v2.0 bug # 31952 */
24362306a36Sopenharmony_ci	if (is_ab8500_2p0(ab->ab8500)) {
24462306a36Sopenharmony_ci		abx500_mask_and_set_register_interruptible(ab->dev,
24562306a36Sopenharmony_ci				AB8500_USB, AB8500_USB_PHY_CTRL_REG,
24662306a36Sopenharmony_ci				bit, bit);
24762306a36Sopenharmony_ci		udelay(AB8500_V20_31952_DISABLE_DELAY_US);
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	u8 bit;
25462306a36Sopenharmony_ci	bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
25562306a36Sopenharmony_ci		AB8500_BIT_PHY_CTRL_DEVICE_EN;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* mux and configure USB pins to DEFAULT state */
25862306a36Sopenharmony_ci	ab->pinctrl = pinctrl_get_select(ab->dev, PINCTRL_STATE_DEFAULT);
25962306a36Sopenharmony_ci	if (IS_ERR(ab->pinctrl))
26062306a36Sopenharmony_ci		dev_err(ab->dev, "could not get/set default pinstate\n");
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (clk_prepare_enable(ab->sysclk))
26362306a36Sopenharmony_ci		dev_err(ab->dev, "can't prepare/enable clock\n");
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ab8500_usb_regulator_enable(ab);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	abx500_mask_and_set_register_interruptible(ab->dev,
26862306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_PHY_CTRL_REG,
26962306a36Sopenharmony_ci			bit, bit);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	u8 bit;
27562306a36Sopenharmony_ci	bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
27662306a36Sopenharmony_ci		AB8500_BIT_PHY_CTRL_DEVICE_EN;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	ab8500_usb_wd_linkstatus(ab, bit);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	abx500_mask_and_set_register_interruptible(ab->dev,
28162306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_PHY_CTRL_REG,
28262306a36Sopenharmony_ci			bit, 0);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	/* Needed to disable the phy.*/
28562306a36Sopenharmony_ci	ab8500_usb_wd_workaround(ab);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	clk_disable_unprepare(ab->sysclk);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ab8500_usb_regulator_disable(ab);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (!IS_ERR(ab->pinctrl)) {
29262306a36Sopenharmony_ci		/* configure USB pins to SLEEP state */
29362306a36Sopenharmony_ci		ab->pins_sleep = pinctrl_lookup_state(ab->pinctrl,
29462306a36Sopenharmony_ci				PINCTRL_STATE_SLEEP);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		if (IS_ERR(ab->pins_sleep))
29762306a36Sopenharmony_ci			dev_dbg(ab->dev, "could not get sleep pinstate\n");
29862306a36Sopenharmony_ci		else if (pinctrl_select_state(ab->pinctrl, ab->pins_sleep))
29962306a36Sopenharmony_ci			dev_err(ab->dev, "could not set pins to sleep state\n");
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		/*
30262306a36Sopenharmony_ci		 * as USB pins are shared with iddet, release them to allow
30362306a36Sopenharmony_ci		 * iddet to request them
30462306a36Sopenharmony_ci		 */
30562306a36Sopenharmony_ci		pinctrl_put(ab->pinctrl);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci#define ab8500_usb_host_phy_en(ab)	ab8500_usb_phy_enable(ab, true)
31062306a36Sopenharmony_ci#define ab8500_usb_host_phy_dis(ab)	ab8500_usb_phy_disable(ab, true)
31162306a36Sopenharmony_ci#define ab8500_usb_peri_phy_en(ab)	ab8500_usb_phy_enable(ab, false)
31262306a36Sopenharmony_ci#define ab8500_usb_peri_phy_dis(ab)	ab8500_usb_phy_disable(ab, false)
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int ab8505_usb_link_status_update(struct ab8500_usb *ab,
31562306a36Sopenharmony_ci		enum ab8505_usb_link_status lsts)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	enum ux500_musb_vbus_id_status event = 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/*
32262306a36Sopenharmony_ci	 * Spurious link_status interrupts are seen at the time of
32362306a36Sopenharmony_ci	 * disconnection of a device in RIDA state
32462306a36Sopenharmony_ci	 */
32562306a36Sopenharmony_ci	if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 &&
32662306a36Sopenharmony_ci			(lsts == USB_LINK_STD_HOST_NC_8505))
32762306a36Sopenharmony_ci		return 0;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ab->previous_link_status_state = lsts;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	switch (lsts) {
33262306a36Sopenharmony_ci	case USB_LINK_ACA_RID_B_8505:
33362306a36Sopenharmony_ci		event = UX500_MUSB_RIDB;
33462306a36Sopenharmony_ci		fallthrough;
33562306a36Sopenharmony_ci	case USB_LINK_NOT_CONFIGURED_8505:
33662306a36Sopenharmony_ci	case USB_LINK_RESERVED0_8505:
33762306a36Sopenharmony_ci	case USB_LINK_RESERVED1_8505:
33862306a36Sopenharmony_ci	case USB_LINK_RESERVED2_8505:
33962306a36Sopenharmony_ci	case USB_LINK_RESERVED3_8505:
34062306a36Sopenharmony_ci		ab->mode = USB_IDLE;
34162306a36Sopenharmony_ci		ab->phy.otg->default_a = false;
34262306a36Sopenharmony_ci		ab->vbus_draw = 0;
34362306a36Sopenharmony_ci		if (event != UX500_MUSB_RIDB)
34462306a36Sopenharmony_ci			event = UX500_MUSB_NONE;
34562306a36Sopenharmony_ci		/*
34662306a36Sopenharmony_ci		 * Fallback to default B_IDLE as nothing
34762306a36Sopenharmony_ci		 * is connected
34862306a36Sopenharmony_ci		 */
34962306a36Sopenharmony_ci		ab->phy.otg->state = OTG_STATE_B_IDLE;
35062306a36Sopenharmony_ci		usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
35162306a36Sopenharmony_ci		break;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	case USB_LINK_ACA_RID_C_NM_8505:
35462306a36Sopenharmony_ci		event = UX500_MUSB_RIDC;
35562306a36Sopenharmony_ci		fallthrough;
35662306a36Sopenharmony_ci	case USB_LINK_STD_HOST_NC_8505:
35762306a36Sopenharmony_ci	case USB_LINK_STD_HOST_C_NS_8505:
35862306a36Sopenharmony_ci	case USB_LINK_STD_HOST_C_S_8505:
35962306a36Sopenharmony_ci	case USB_LINK_CDP_8505:
36062306a36Sopenharmony_ci		if (ab->mode == USB_IDLE) {
36162306a36Sopenharmony_ci			ab->mode = USB_PERIPHERAL;
36262306a36Sopenharmony_ci			ab8500_usb_peri_phy_en(ab);
36362306a36Sopenharmony_ci			atomic_notifier_call_chain(&ab->phy.notifier,
36462306a36Sopenharmony_ci					UX500_MUSB_PREPARE, &ab->vbus_draw);
36562306a36Sopenharmony_ci			usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci		if (event != UX500_MUSB_RIDC)
36862306a36Sopenharmony_ci			event = UX500_MUSB_VBUS;
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	case USB_LINK_ACA_RID_A_8505:
37262306a36Sopenharmony_ci	case USB_LINK_ACA_DOCK_CHGR_8505:
37362306a36Sopenharmony_ci		event = UX500_MUSB_RIDA;
37462306a36Sopenharmony_ci		fallthrough;
37562306a36Sopenharmony_ci	case USB_LINK_HM_IDGND_8505:
37662306a36Sopenharmony_ci		if (ab->mode == USB_IDLE) {
37762306a36Sopenharmony_ci			ab->mode = USB_HOST;
37862306a36Sopenharmony_ci			ab8500_usb_host_phy_en(ab);
37962306a36Sopenharmony_ci			atomic_notifier_call_chain(&ab->phy.notifier,
38062306a36Sopenharmony_ci					UX500_MUSB_PREPARE, &ab->vbus_draw);
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci		ab->phy.otg->default_a = true;
38362306a36Sopenharmony_ci		if (event != UX500_MUSB_RIDA)
38462306a36Sopenharmony_ci			event = UX500_MUSB_ID;
38562306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
38662306a36Sopenharmony_ci				event, &ab->vbus_draw);
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	case USB_LINK_DEDICATED_CHG_8505:
39062306a36Sopenharmony_ci		ab->mode = USB_DEDICATED_CHG;
39162306a36Sopenharmony_ci		event = UX500_MUSB_CHARGER;
39262306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
39362306a36Sopenharmony_ci				event, &ab->vbus_draw);
39462306a36Sopenharmony_ci		usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * FIXME: For now we rely on the boot firmware to set up the necessary
39962306a36Sopenharmony_ci	 * PHY/pin configuration for UART mode.
40062306a36Sopenharmony_ci	 *
40162306a36Sopenharmony_ci	 * AB8505 does not seem to report any status change for UART cables,
40262306a36Sopenharmony_ci	 * possibly because it cannot detect them autonomously.
40362306a36Sopenharmony_ci	 * We may need to measure the ID resistance manually to reliably
40462306a36Sopenharmony_ci	 * detect UART cables after bootup.
40562306a36Sopenharmony_ci	 */
40662306a36Sopenharmony_ci	case USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505:
40762306a36Sopenharmony_ci	case USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505:
40862306a36Sopenharmony_ci		if (ab->mode == USB_IDLE) {
40962306a36Sopenharmony_ci			ab->mode = USB_UART;
41062306a36Sopenharmony_ci			ab8500_usb_peri_phy_en(ab);
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		break;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	default:
41662306a36Sopenharmony_ci		break;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int ab8500_usb_link_status_update(struct ab8500_usb *ab,
42362306a36Sopenharmony_ci		enum ab8500_usb_link_status lsts)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	enum ux500_musb_vbus_id_status event = 0;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/*
43062306a36Sopenharmony_ci	 * Spurious link_status interrupts are seen in case of a
43162306a36Sopenharmony_ci	 * disconnection of a device in IDGND and RIDA stage
43262306a36Sopenharmony_ci	 */
43362306a36Sopenharmony_ci	if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 &&
43462306a36Sopenharmony_ci			(lsts == USB_LINK_STD_HOST_C_NS_8500 ||
43562306a36Sopenharmony_ci			 lsts == USB_LINK_STD_HOST_NC_8500))
43662306a36Sopenharmony_ci		return 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 &&
43962306a36Sopenharmony_ci			lsts == USB_LINK_STD_HOST_NC_8500)
44062306a36Sopenharmony_ci		return 0;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	ab->previous_link_status_state = lsts;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	switch (lsts) {
44562306a36Sopenharmony_ci	case USB_LINK_ACA_RID_B_8500:
44662306a36Sopenharmony_ci		event = UX500_MUSB_RIDB;
44762306a36Sopenharmony_ci		fallthrough;
44862306a36Sopenharmony_ci	case USB_LINK_NOT_CONFIGURED_8500:
44962306a36Sopenharmony_ci	case USB_LINK_NOT_VALID_LINK_8500:
45062306a36Sopenharmony_ci		ab->mode = USB_IDLE;
45162306a36Sopenharmony_ci		ab->phy.otg->default_a = false;
45262306a36Sopenharmony_ci		ab->vbus_draw = 0;
45362306a36Sopenharmony_ci		if (event != UX500_MUSB_RIDB)
45462306a36Sopenharmony_ci			event = UX500_MUSB_NONE;
45562306a36Sopenharmony_ci		/* Fallback to default B_IDLE as nothing is connected */
45662306a36Sopenharmony_ci		ab->phy.otg->state = OTG_STATE_B_IDLE;
45762306a36Sopenharmony_ci		usb_phy_set_event(&ab->phy, USB_EVENT_NONE);
45862306a36Sopenharmony_ci		break;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	case USB_LINK_ACA_RID_C_NM_8500:
46162306a36Sopenharmony_ci	case USB_LINK_ACA_RID_C_HS_8500:
46262306a36Sopenharmony_ci	case USB_LINK_ACA_RID_C_HS_CHIRP_8500:
46362306a36Sopenharmony_ci		event = UX500_MUSB_RIDC;
46462306a36Sopenharmony_ci		fallthrough;
46562306a36Sopenharmony_ci	case USB_LINK_STD_HOST_NC_8500:
46662306a36Sopenharmony_ci	case USB_LINK_STD_HOST_C_NS_8500:
46762306a36Sopenharmony_ci	case USB_LINK_STD_HOST_C_S_8500:
46862306a36Sopenharmony_ci	case USB_LINK_HOST_CHG_NM_8500:
46962306a36Sopenharmony_ci	case USB_LINK_HOST_CHG_HS_8500:
47062306a36Sopenharmony_ci	case USB_LINK_HOST_CHG_HS_CHIRP_8500:
47162306a36Sopenharmony_ci		if (ab->mode == USB_IDLE) {
47262306a36Sopenharmony_ci			ab->mode = USB_PERIPHERAL;
47362306a36Sopenharmony_ci			ab8500_usb_peri_phy_en(ab);
47462306a36Sopenharmony_ci			atomic_notifier_call_chain(&ab->phy.notifier,
47562306a36Sopenharmony_ci					UX500_MUSB_PREPARE, &ab->vbus_draw);
47662306a36Sopenharmony_ci			usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci		if (event != UX500_MUSB_RIDC)
47962306a36Sopenharmony_ci			event = UX500_MUSB_VBUS;
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	case USB_LINK_ACA_RID_A_8500:
48362306a36Sopenharmony_ci		event = UX500_MUSB_RIDA;
48462306a36Sopenharmony_ci		fallthrough;
48562306a36Sopenharmony_ci	case USB_LINK_HM_IDGND_8500:
48662306a36Sopenharmony_ci		if (ab->mode == USB_IDLE) {
48762306a36Sopenharmony_ci			ab->mode = USB_HOST;
48862306a36Sopenharmony_ci			ab8500_usb_host_phy_en(ab);
48962306a36Sopenharmony_ci			atomic_notifier_call_chain(&ab->phy.notifier,
49062306a36Sopenharmony_ci					UX500_MUSB_PREPARE, &ab->vbus_draw);
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci		ab->phy.otg->default_a = true;
49362306a36Sopenharmony_ci		if (event != UX500_MUSB_RIDA)
49462306a36Sopenharmony_ci			event = UX500_MUSB_ID;
49562306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
49662306a36Sopenharmony_ci				event, &ab->vbus_draw);
49762306a36Sopenharmony_ci		break;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	case USB_LINK_DEDICATED_CHG_8500:
50062306a36Sopenharmony_ci		ab->mode = USB_DEDICATED_CHG;
50162306a36Sopenharmony_ci		event = UX500_MUSB_CHARGER;
50262306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
50362306a36Sopenharmony_ci				event, &ab->vbus_draw);
50462306a36Sopenharmony_ci		usb_phy_set_event(&ab->phy, USB_EVENT_CHARGER);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	case USB_LINK_RESERVED_8500:
50862306a36Sopenharmony_ci		break;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	return 0;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci/*
51562306a36Sopenharmony_ci * Connection Sequence:
51662306a36Sopenharmony_ci *   1. Link Status Interrupt
51762306a36Sopenharmony_ci *   2. Enable AB clock
51862306a36Sopenharmony_ci *   3. Enable AB regulators
51962306a36Sopenharmony_ci *   4. Enable USB phy
52062306a36Sopenharmony_ci *   5. Reset the musb controller
52162306a36Sopenharmony_ci *   6. Switch the ULPI GPIO pins to function mode
52262306a36Sopenharmony_ci *   7. Enable the musb Peripheral5 clock
52362306a36Sopenharmony_ci *   8. Restore MUSB context
52462306a36Sopenharmony_ci */
52562306a36Sopenharmony_cistatic int abx500_usb_link_status_update(struct ab8500_usb *ab)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	u8 reg;
52862306a36Sopenharmony_ci	int ret = 0;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (is_ab8500(ab->ab8500)) {
53162306a36Sopenharmony_ci		enum ab8500_usb_link_status lsts;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(ab->dev,
53462306a36Sopenharmony_ci				AB8500_USB, AB8500_USB_LINE_STAT_REG, &reg);
53562306a36Sopenharmony_ci		if (ret < 0)
53662306a36Sopenharmony_ci			return ret;
53762306a36Sopenharmony_ci		lsts = (reg >> 3) & 0x0F;
53862306a36Sopenharmony_ci		ret = ab8500_usb_link_status_update(ab, lsts);
53962306a36Sopenharmony_ci	} else if (is_ab8505(ab->ab8500)) {
54062306a36Sopenharmony_ci		enum ab8505_usb_link_status lsts;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		ret = abx500_get_register_interruptible(ab->dev,
54362306a36Sopenharmony_ci				AB8500_USB, AB8505_USB_LINE_STAT_REG, &reg);
54462306a36Sopenharmony_ci		if (ret < 0)
54562306a36Sopenharmony_ci			return ret;
54662306a36Sopenharmony_ci		lsts = (reg >> 3) & 0x1F;
54762306a36Sopenharmony_ci		ret = ab8505_usb_link_status_update(ab, lsts);
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	return ret;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/*
55462306a36Sopenharmony_ci * Disconnection Sequence:
55562306a36Sopenharmony_ci *   1. Disconnect Interrupt
55662306a36Sopenharmony_ci *   2. Disable regulators
55762306a36Sopenharmony_ci *   3. Disable AB clock
55862306a36Sopenharmony_ci *   4. Disable the Phy
55962306a36Sopenharmony_ci *   5. Link Status Interrupt
56062306a36Sopenharmony_ci *   6. Disable Musb Clock
56162306a36Sopenharmony_ci */
56262306a36Sopenharmony_cistatic irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct ab8500_usb *ab = (struct ab8500_usb *) data;
56562306a36Sopenharmony_ci	enum usb_phy_events event = USB_EVENT_NONE;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/* Link status will not be updated till phy is disabled. */
56862306a36Sopenharmony_ci	if (ab->mode == USB_HOST) {
56962306a36Sopenharmony_ci		ab->phy.otg->default_a = false;
57062306a36Sopenharmony_ci		ab->vbus_draw = 0;
57162306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
57262306a36Sopenharmony_ci				event, &ab->vbus_draw);
57362306a36Sopenharmony_ci		ab8500_usb_host_phy_dis(ab);
57462306a36Sopenharmony_ci		ab->mode = USB_IDLE;
57562306a36Sopenharmony_ci	}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (ab->mode == USB_PERIPHERAL) {
57862306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
57962306a36Sopenharmony_ci				event, &ab->vbus_draw);
58062306a36Sopenharmony_ci		ab8500_usb_peri_phy_dis(ab);
58162306a36Sopenharmony_ci		atomic_notifier_call_chain(&ab->phy.notifier,
58262306a36Sopenharmony_ci				UX500_MUSB_CLEAN, &ab->vbus_draw);
58362306a36Sopenharmony_ci		ab->mode = USB_IDLE;
58462306a36Sopenharmony_ci		ab->phy.otg->default_a = false;
58562306a36Sopenharmony_ci		ab->vbus_draw = 0;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (ab->mode == USB_UART) {
58962306a36Sopenharmony_ci		ab8500_usb_peri_phy_dis(ab);
59062306a36Sopenharmony_ci		ab->mode = USB_IDLE;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (is_ab8500_2p0(ab->ab8500)) {
59462306a36Sopenharmony_ci		if (ab->mode == USB_DEDICATED_CHG) {
59562306a36Sopenharmony_ci			ab8500_usb_wd_linkstatus(ab,
59662306a36Sopenharmony_ci					AB8500_BIT_PHY_CTRL_DEVICE_EN);
59762306a36Sopenharmony_ci			abx500_mask_and_set_register_interruptible(ab->dev,
59862306a36Sopenharmony_ci					AB8500_USB, AB8500_USB_PHY_CTRL_REG,
59962306a36Sopenharmony_ci					AB8500_BIT_PHY_CTRL_DEVICE_EN, 0);
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	return IRQ_HANDLED;
60462306a36Sopenharmony_ci}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_cistatic irqreturn_t ab8500_usb_link_status_irq(int irq, void *data)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	struct ab8500_usb *ab = (struct ab8500_usb *)data;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	abx500_usb_link_status_update(ab);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return IRQ_HANDLED;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic void ab8500_usb_phy_disable_work(struct work_struct *work)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
61862306a36Sopenharmony_ci						phy_dis_work);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (!ab->phy.otg->host)
62162306a36Sopenharmony_ci		ab8500_usb_host_phy_dis(ab);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (!ab->phy.otg->gadget)
62462306a36Sopenharmony_ci		ab8500_usb_peri_phy_dis(ab);
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	/* TODO */
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int ab8500_usb_set_peripheral(struct usb_otg *otg,
63462306a36Sopenharmony_ci					struct usb_gadget *gadget)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	struct ab8500_usb *ab;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (!otg)
63962306a36Sopenharmony_ci		return -ENODEV;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	ab = phy_to_ab(otg->usb_phy);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	ab->phy.otg->gadget = gadget;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* Some drivers call this function in atomic context.
64662306a36Sopenharmony_ci	 * Do not update ab8500 registers directly till this
64762306a36Sopenharmony_ci	 * is fixed.
64862306a36Sopenharmony_ci	 */
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if ((ab->mode != USB_IDLE) && !gadget) {
65162306a36Sopenharmony_ci		ab->mode = USB_IDLE;
65262306a36Sopenharmony_ci		schedule_work(&ab->phy_dis_work);
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	return 0;
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct ab8500_usb *ab;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (!otg)
66362306a36Sopenharmony_ci		return -ENODEV;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	ab = phy_to_ab(otg->usb_phy);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	ab->phy.otg->host = host;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* Some drivers call this function in atomic context.
67062306a36Sopenharmony_ci	 * Do not update ab8500 registers directly till this
67162306a36Sopenharmony_ci	 * is fixed.
67262306a36Sopenharmony_ci	 */
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if ((ab->mode != USB_IDLE) && !host) {
67562306a36Sopenharmony_ci		ab->mode = USB_IDLE;
67662306a36Sopenharmony_ci		schedule_work(&ab->phy_dis_work);
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	return 0;
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic void ab8500_usb_restart_phy(struct ab8500_usb *ab)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	abx500_mask_and_set_register_interruptible(ab->dev,
68562306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_PHY_CTRL_REG,
68662306a36Sopenharmony_ci			AB8500_BIT_PHY_CTRL_DEVICE_EN,
68762306a36Sopenharmony_ci			AB8500_BIT_PHY_CTRL_DEVICE_EN);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	udelay(100);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	abx500_mask_and_set_register_interruptible(ab->dev,
69262306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_PHY_CTRL_REG,
69362306a36Sopenharmony_ci			AB8500_BIT_PHY_CTRL_DEVICE_EN,
69462306a36Sopenharmony_ci			0);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	abx500_mask_and_set_register_interruptible(ab->dev,
69762306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_PHY_CTRL_REG,
69862306a36Sopenharmony_ci			AB8500_BIT_PHY_CTRL_HOST_EN,
69962306a36Sopenharmony_ci			AB8500_BIT_PHY_CTRL_HOST_EN);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	udelay(100);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	abx500_mask_and_set_register_interruptible(ab->dev,
70462306a36Sopenharmony_ci			AB8500_USB, AB8500_USB_PHY_CTRL_REG,
70562306a36Sopenharmony_ci			AB8500_BIT_PHY_CTRL_HOST_EN,
70662306a36Sopenharmony_ci			0);
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cistatic int ab8500_usb_regulator_get(struct ab8500_usb *ab)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	int err;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	ab->v_ape = devm_regulator_get(ab->dev, "v-ape");
71462306a36Sopenharmony_ci	if (IS_ERR(ab->v_ape)) {
71562306a36Sopenharmony_ci		dev_err(ab->dev, "Could not get v-ape supply\n");
71662306a36Sopenharmony_ci		err = PTR_ERR(ab->v_ape);
71762306a36Sopenharmony_ci		return err;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	ab->v_ulpi = devm_regulator_get(ab->dev, "vddulpivio18");
72162306a36Sopenharmony_ci	if (IS_ERR(ab->v_ulpi)) {
72262306a36Sopenharmony_ci		dev_err(ab->dev, "Could not get vddulpivio18 supply\n");
72362306a36Sopenharmony_ci		err = PTR_ERR(ab->v_ulpi);
72462306a36Sopenharmony_ci		return err;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	ab->v_musb = devm_regulator_get(ab->dev, "musb_1v8");
72862306a36Sopenharmony_ci	if (IS_ERR(ab->v_musb)) {
72962306a36Sopenharmony_ci		dev_err(ab->dev, "Could not get musb_1v8 supply\n");
73062306a36Sopenharmony_ci		err = PTR_ERR(ab->v_musb);
73162306a36Sopenharmony_ci		return err;
73262306a36Sopenharmony_ci	}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	return 0;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic int ab8500_usb_irq_setup(struct platform_device *pdev,
73862306a36Sopenharmony_ci		struct ab8500_usb *ab)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	int err;
74162306a36Sopenharmony_ci	int irq;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (ab->flags & AB8500_USB_FLAG_USE_LINK_STATUS_IRQ) {
74462306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS");
74562306a36Sopenharmony_ci		if (irq < 0)
74662306a36Sopenharmony_ci			return irq;
74762306a36Sopenharmony_ci		err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
74862306a36Sopenharmony_ci				ab8500_usb_link_status_irq,
74962306a36Sopenharmony_ci				IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT,
75062306a36Sopenharmony_ci				"usb-link-status", ab);
75162306a36Sopenharmony_ci		if (err < 0) {
75262306a36Sopenharmony_ci			dev_err(ab->dev, "request_irq failed for link status irq\n");
75362306a36Sopenharmony_ci			return err;
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (ab->flags & AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ) {
75862306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
75962306a36Sopenharmony_ci		if (irq < 0)
76062306a36Sopenharmony_ci			return irq;
76162306a36Sopenharmony_ci		err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
76262306a36Sopenharmony_ci				ab8500_usb_disconnect_irq,
76362306a36Sopenharmony_ci				IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT,
76462306a36Sopenharmony_ci				"usb-id-fall", ab);
76562306a36Sopenharmony_ci		if (err < 0) {
76662306a36Sopenharmony_ci			dev_err(ab->dev, "request_irq failed for ID fall irq\n");
76762306a36Sopenharmony_ci			return err;
76862306a36Sopenharmony_ci		}
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (ab->flags & AB8500_USB_FLAG_USE_VBUS_DET_IRQ) {
77262306a36Sopenharmony_ci		irq = platform_get_irq_byname(pdev, "VBUS_DET_F");
77362306a36Sopenharmony_ci		if (irq < 0)
77462306a36Sopenharmony_ci			return irq;
77562306a36Sopenharmony_ci		err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
77662306a36Sopenharmony_ci				ab8500_usb_disconnect_irq,
77762306a36Sopenharmony_ci				IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT,
77862306a36Sopenharmony_ci				"usb-vbus-fall", ab);
77962306a36Sopenharmony_ci		if (err < 0) {
78062306a36Sopenharmony_ci			dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
78162306a36Sopenharmony_ci			return err;
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistatic void ab8500_usb_set_ab8500_tuning_values(struct ab8500_usb *ab)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	int err;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/* Enable the PBT/Bank 0x12 access */
79362306a36Sopenharmony_ci	err = abx500_set_register_interruptible(ab->dev,
79462306a36Sopenharmony_ci			AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01);
79562306a36Sopenharmony_ci	if (err < 0)
79662306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
79762306a36Sopenharmony_ci				err);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	err = abx500_set_register_interruptible(ab->dev,
80062306a36Sopenharmony_ci			AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8);
80162306a36Sopenharmony_ci	if (err < 0)
80262306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
80362306a36Sopenharmony_ci				err);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	err = abx500_set_register_interruptible(ab->dev,
80662306a36Sopenharmony_ci			AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x00);
80762306a36Sopenharmony_ci	if (err < 0)
80862306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
80962306a36Sopenharmony_ci				err);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	err = abx500_set_register_interruptible(ab->dev,
81262306a36Sopenharmony_ci			AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78);
81362306a36Sopenharmony_ci	if (err < 0)
81462306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n",
81562306a36Sopenharmony_ci				err);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* Switch to normal mode/disable Bank 0x12 access */
81862306a36Sopenharmony_ci	err = abx500_set_register_interruptible(ab->dev,
81962306a36Sopenharmony_ci			AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00);
82062306a36Sopenharmony_ci	if (err < 0)
82162306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
82262306a36Sopenharmony_ci				err);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic void ab8500_usb_set_ab8505_tuning_values(struct ab8500_usb *ab)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	int err;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	/* Enable the PBT/Bank 0x12 access */
83062306a36Sopenharmony_ci	err = abx500_mask_and_set_register_interruptible(ab->dev,
83162306a36Sopenharmony_ci			AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
83262306a36Sopenharmony_ci			0x01, 0x01);
83362306a36Sopenharmony_ci	if (err < 0)
83462306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
83562306a36Sopenharmony_ci				err);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	err = abx500_mask_and_set_register_interruptible(ab->dev,
83862306a36Sopenharmony_ci			AB8500_DEBUG, AB8500_USB_PHY_TUNE1,
83962306a36Sopenharmony_ci			0xC8, 0xC8);
84062306a36Sopenharmony_ci	if (err < 0)
84162306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
84262306a36Sopenharmony_ci				err);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	err = abx500_mask_and_set_register_interruptible(ab->dev,
84562306a36Sopenharmony_ci			AB8500_DEBUG, AB8500_USB_PHY_TUNE2,
84662306a36Sopenharmony_ci			0x60, 0x60);
84762306a36Sopenharmony_ci	if (err < 0)
84862306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
84962306a36Sopenharmony_ci				err);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	err = abx500_mask_and_set_register_interruptible(ab->dev,
85262306a36Sopenharmony_ci			AB8500_DEBUG, AB8500_USB_PHY_TUNE3,
85362306a36Sopenharmony_ci			0xFC, 0x80);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (err < 0)
85662306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n",
85762306a36Sopenharmony_ci				err);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/* Switch to normal mode/disable Bank 0x12 access */
86062306a36Sopenharmony_ci	err = abx500_mask_and_set_register_interruptible(ab->dev,
86162306a36Sopenharmony_ci			AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
86262306a36Sopenharmony_ci			0x00, 0x00);
86362306a36Sopenharmony_ci	if (err < 0)
86462306a36Sopenharmony_ci		dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
86562306a36Sopenharmony_ci				err);
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic int ab8500_usb_probe(struct platform_device *pdev)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	struct ab8500_usb	*ab;
87162306a36Sopenharmony_ci	struct ab8500		*ab8500;
87262306a36Sopenharmony_ci	struct usb_otg		*otg;
87362306a36Sopenharmony_ci	int err;
87462306a36Sopenharmony_ci	int rev;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	ab8500 = dev_get_drvdata(pdev->dev.parent);
87762306a36Sopenharmony_ci	rev = abx500_get_chip_id(&pdev->dev);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (is_ab8500_1p1_or_earlier(ab8500)) {
88062306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev);
88162306a36Sopenharmony_ci		return -ENODEV;
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	ab = devm_kzalloc(&pdev->dev, sizeof(*ab), GFP_KERNEL);
88562306a36Sopenharmony_ci	if (!ab)
88662306a36Sopenharmony_ci		return -ENOMEM;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
88962306a36Sopenharmony_ci	if (!otg)
89062306a36Sopenharmony_ci		return -ENOMEM;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	ab->dev			= &pdev->dev;
89362306a36Sopenharmony_ci	ab->ab8500		= ab8500;
89462306a36Sopenharmony_ci	ab->phy.dev		= ab->dev;
89562306a36Sopenharmony_ci	ab->phy.otg		= otg;
89662306a36Sopenharmony_ci	ab->phy.label		= "ab8500";
89762306a36Sopenharmony_ci	ab->phy.set_suspend	= ab8500_usb_set_suspend;
89862306a36Sopenharmony_ci	ab->phy.otg->state	= OTG_STATE_UNDEFINED;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	otg->usb_phy		= &ab->phy;
90162306a36Sopenharmony_ci	otg->set_host		= ab8500_usb_set_host;
90262306a36Sopenharmony_ci	otg->set_peripheral	= ab8500_usb_set_peripheral;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (is_ab8500(ab->ab8500)) {
90562306a36Sopenharmony_ci		ab->flags |= AB8500_USB_FLAG_USE_LINK_STATUS_IRQ |
90662306a36Sopenharmony_ci			AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ |
90762306a36Sopenharmony_ci			AB8500_USB_FLAG_USE_VBUS_DET_IRQ |
90862306a36Sopenharmony_ci			AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
90962306a36Sopenharmony_ci	} else if (is_ab8505(ab->ab8500)) {
91062306a36Sopenharmony_ci		ab->flags |= AB8500_USB_FLAG_USE_LINK_STATUS_IRQ |
91162306a36Sopenharmony_ci			AB8500_USB_FLAG_USE_ID_WAKEUP_IRQ |
91262306a36Sopenharmony_ci			AB8500_USB_FLAG_USE_VBUS_DET_IRQ |
91362306a36Sopenharmony_ci			AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* Disable regulator voltage setting for AB8500 <= v2.0 */
91762306a36Sopenharmony_ci	if (is_ab8500_2p0_or_earlier(ab->ab8500))
91862306a36Sopenharmony_ci		ab->flags &= ~AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	platform_set_drvdata(pdev, ab);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/* all: Disable phy when called from set_host and set_peripheral */
92362306a36Sopenharmony_ci	INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	err = ab8500_usb_regulator_get(ab);
92662306a36Sopenharmony_ci	if (err)
92762306a36Sopenharmony_ci		return err;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	ab->sysclk = devm_clk_get(ab->dev, "sysclk");
93062306a36Sopenharmony_ci	if (IS_ERR(ab->sysclk)) {
93162306a36Sopenharmony_ci		dev_err(ab->dev, "Could not get sysclk.\n");
93262306a36Sopenharmony_ci		return PTR_ERR(ab->sysclk);
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	err = ab8500_usb_irq_setup(pdev, ab);
93662306a36Sopenharmony_ci	if (err < 0)
93762306a36Sopenharmony_ci		return err;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
94062306a36Sopenharmony_ci	if (err) {
94162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can't register transceiver\n");
94262306a36Sopenharmony_ci		return err;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	if (is_ab8500(ab->ab8500) && !is_ab8500_2p0_or_earlier(ab->ab8500))
94662306a36Sopenharmony_ci		/* Phy tuning values for AB8500 > v2.0 */
94762306a36Sopenharmony_ci		ab8500_usb_set_ab8500_tuning_values(ab);
94862306a36Sopenharmony_ci	else if (is_ab8505(ab->ab8500))
94962306a36Sopenharmony_ci		/* Phy tuning values for AB8505 */
95062306a36Sopenharmony_ci		ab8500_usb_set_ab8505_tuning_values(ab);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	/* Needed to enable ID detection. */
95362306a36Sopenharmony_ci	ab8500_usb_wd_workaround(ab);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/*
95662306a36Sopenharmony_ci	 * This is required for usb-link-status to work properly when a
95762306a36Sopenharmony_ci	 * cable is connected at boot time.
95862306a36Sopenharmony_ci	 */
95962306a36Sopenharmony_ci	ab8500_usb_restart_phy(ab);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	abx500_usb_link_status_update(ab);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic void ab8500_usb_remove(struct platform_device *pdev)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct ab8500_usb *ab = platform_get_drvdata(pdev);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	cancel_work_sync(&ab->phy_dis_work);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	usb_remove_phy(&ab->phy);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if (ab->mode == USB_HOST)
97762306a36Sopenharmony_ci		ab8500_usb_host_phy_dis(ab);
97862306a36Sopenharmony_ci	else if (ab->mode == USB_PERIPHERAL)
97962306a36Sopenharmony_ci		ab8500_usb_peri_phy_dis(ab);
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic const struct platform_device_id ab8500_usb_devtype[] = {
98362306a36Sopenharmony_ci	{ .name = "ab8500-usb", },
98462306a36Sopenharmony_ci	{ /* sentinel */ }
98562306a36Sopenharmony_ci};
98662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, ab8500_usb_devtype);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic struct platform_driver ab8500_usb_driver = {
98962306a36Sopenharmony_ci	.probe		= ab8500_usb_probe,
99062306a36Sopenharmony_ci	.remove_new	= ab8500_usb_remove,
99162306a36Sopenharmony_ci	.id_table	= ab8500_usb_devtype,
99262306a36Sopenharmony_ci	.driver		= {
99362306a36Sopenharmony_ci		.name	= "abx5x0-usb",
99462306a36Sopenharmony_ci	},
99562306a36Sopenharmony_ci};
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic int __init ab8500_usb_init(void)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	return platform_driver_register(&ab8500_usb_driver);
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_cisubsys_initcall(ab8500_usb_init);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic void __exit ab8500_usb_exit(void)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	platform_driver_unregister(&ab8500_usb_driver);
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_cimodule_exit(ab8500_usb_exit);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ciMODULE_AUTHOR("ST-Ericsson AB");
101062306a36Sopenharmony_ciMODULE_DESCRIPTION("AB8500 family usb transceiver driver");
101162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1012