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, ®); 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, ®); 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