162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Rockchip USB2.0 PHY with Innosilicon IP block driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/clk-provider.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/extcon-provider.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1562306a36Sopenharmony_ci#include <linux/jiffies.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci#include <linux/of.h> 2062306a36Sopenharmony_ci#include <linux/of_address.h> 2162306a36Sopenharmony_ci#include <linux/of_irq.h> 2262306a36Sopenharmony_ci#include <linux/of_platform.h> 2362306a36Sopenharmony_ci#include <linux/phy/phy.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/power_supply.h> 2662306a36Sopenharmony_ci#include <linux/regmap.h> 2762306a36Sopenharmony_ci#include <linux/reset.h> 2862306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2962306a36Sopenharmony_ci#include <linux/usb/of.h> 3062306a36Sopenharmony_ci#include <linux/usb/otg.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define BIT_WRITEABLE_SHIFT 16 3362306a36Sopenharmony_ci#define SCHEDULE_DELAY (60 * HZ) 3462306a36Sopenharmony_ci#define OTG_SCHEDULE_DELAY (2 * HZ) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct rockchip_usb2phy; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cienum rockchip_usb2phy_port_id { 3962306a36Sopenharmony_ci USB2PHY_PORT_OTG, 4062306a36Sopenharmony_ci USB2PHY_PORT_HOST, 4162306a36Sopenharmony_ci USB2PHY_NUM_PORTS, 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cienum rockchip_usb2phy_host_state { 4562306a36Sopenharmony_ci PHY_STATE_HS_ONLINE = 0, 4662306a36Sopenharmony_ci PHY_STATE_DISCONNECT = 1, 4762306a36Sopenharmony_ci PHY_STATE_CONNECT = 2, 4862306a36Sopenharmony_ci PHY_STATE_FS_LS_ONLINE = 4, 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * enum usb_chg_state - Different states involved in USB charger detection. 5362306a36Sopenharmony_ci * @USB_CHG_STATE_UNDEFINED: USB charger is not connected or detection 5462306a36Sopenharmony_ci * process is not yet started. 5562306a36Sopenharmony_ci * @USB_CHG_STATE_WAIT_FOR_DCD: Waiting for Data pins contact. 5662306a36Sopenharmony_ci * @USB_CHG_STATE_DCD_DONE: Data pin contact is detected. 5762306a36Sopenharmony_ci * @USB_CHG_STATE_PRIMARY_DONE: Primary detection is completed (Detects 5862306a36Sopenharmony_ci * between SDP and DCP/CDP). 5962306a36Sopenharmony_ci * @USB_CHG_STATE_SECONDARY_DONE: Secondary detection is completed (Detects 6062306a36Sopenharmony_ci * between DCP and CDP). 6162306a36Sopenharmony_ci * @USB_CHG_STATE_DETECTED: USB charger type is determined. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cienum usb_chg_state { 6462306a36Sopenharmony_ci USB_CHG_STATE_UNDEFINED = 0, 6562306a36Sopenharmony_ci USB_CHG_STATE_WAIT_FOR_DCD, 6662306a36Sopenharmony_ci USB_CHG_STATE_DCD_DONE, 6762306a36Sopenharmony_ci USB_CHG_STATE_PRIMARY_DONE, 6862306a36Sopenharmony_ci USB_CHG_STATE_SECONDARY_DONE, 6962306a36Sopenharmony_ci USB_CHG_STATE_DETECTED, 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic const unsigned int rockchip_usb2phy_extcon_cable[] = { 7362306a36Sopenharmony_ci EXTCON_USB, 7462306a36Sopenharmony_ci EXTCON_USB_HOST, 7562306a36Sopenharmony_ci EXTCON_CHG_USB_SDP, 7662306a36Sopenharmony_ci EXTCON_CHG_USB_CDP, 7762306a36Sopenharmony_ci EXTCON_CHG_USB_DCP, 7862306a36Sopenharmony_ci EXTCON_CHG_USB_SLOW, 7962306a36Sopenharmony_ci EXTCON_NONE, 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct usb2phy_reg { 8362306a36Sopenharmony_ci unsigned int offset; 8462306a36Sopenharmony_ci unsigned int bitend; 8562306a36Sopenharmony_ci unsigned int bitstart; 8662306a36Sopenharmony_ci unsigned int disable; 8762306a36Sopenharmony_ci unsigned int enable; 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/** 9162306a36Sopenharmony_ci * struct rockchip_chg_det_reg - usb charger detect registers 9262306a36Sopenharmony_ci * @cp_det: charging port detected successfully. 9362306a36Sopenharmony_ci * @dcp_det: dedicated charging port detected successfully. 9462306a36Sopenharmony_ci * @dp_det: assert data pin connect successfully. 9562306a36Sopenharmony_ci * @idm_sink_en: open dm sink curren. 9662306a36Sopenharmony_ci * @idp_sink_en: open dp sink current. 9762306a36Sopenharmony_ci * @idp_src_en: open dm source current. 9862306a36Sopenharmony_ci * @rdm_pdwn_en: open dm pull down resistor. 9962306a36Sopenharmony_ci * @vdm_src_en: open dm voltage source. 10062306a36Sopenharmony_ci * @vdp_src_en: open dp voltage source. 10162306a36Sopenharmony_ci * @opmode: utmi operational mode. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistruct rockchip_chg_det_reg { 10462306a36Sopenharmony_ci struct usb2phy_reg cp_det; 10562306a36Sopenharmony_ci struct usb2phy_reg dcp_det; 10662306a36Sopenharmony_ci struct usb2phy_reg dp_det; 10762306a36Sopenharmony_ci struct usb2phy_reg idm_sink_en; 10862306a36Sopenharmony_ci struct usb2phy_reg idp_sink_en; 10962306a36Sopenharmony_ci struct usb2phy_reg idp_src_en; 11062306a36Sopenharmony_ci struct usb2phy_reg rdm_pdwn_en; 11162306a36Sopenharmony_ci struct usb2phy_reg vdm_src_en; 11262306a36Sopenharmony_ci struct usb2phy_reg vdp_src_en; 11362306a36Sopenharmony_ci struct usb2phy_reg opmode; 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * struct rockchip_usb2phy_port_cfg - usb-phy port configuration. 11862306a36Sopenharmony_ci * @phy_sus: phy suspend register. 11962306a36Sopenharmony_ci * @bvalid_det_en: vbus valid rise detection enable register. 12062306a36Sopenharmony_ci * @bvalid_det_st: vbus valid rise detection status register. 12162306a36Sopenharmony_ci * @bvalid_det_clr: vbus valid rise detection clear register. 12262306a36Sopenharmony_ci * @disfall_en: host disconnect fall edge detection enable. 12362306a36Sopenharmony_ci * @disfall_st: host disconnect fall edge detection state. 12462306a36Sopenharmony_ci * @disfall_clr: host disconnect fall edge detection clear. 12562306a36Sopenharmony_ci * @disrise_en: host disconnect rise edge detection enable. 12662306a36Sopenharmony_ci * @disrise_st: host disconnect rise edge detection state. 12762306a36Sopenharmony_ci * @disrise_clr: host disconnect rise edge detection clear. 12862306a36Sopenharmony_ci * @id_det_en: id detection enable register. 12962306a36Sopenharmony_ci * @id_det_st: id detection state register. 13062306a36Sopenharmony_ci * @id_det_clr: id detection clear register. 13162306a36Sopenharmony_ci * @ls_det_en: linestate detection enable register. 13262306a36Sopenharmony_ci * @ls_det_st: linestate detection state register. 13362306a36Sopenharmony_ci * @ls_det_clr: linestate detection clear register. 13462306a36Sopenharmony_ci * @utmi_avalid: utmi vbus avalid status register. 13562306a36Sopenharmony_ci * @utmi_bvalid: utmi vbus bvalid status register. 13662306a36Sopenharmony_ci * @utmi_id: utmi id state register. 13762306a36Sopenharmony_ci * @utmi_ls: utmi linestate state register. 13862306a36Sopenharmony_ci * @utmi_hstdet: utmi host disconnect register. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_cistruct rockchip_usb2phy_port_cfg { 14162306a36Sopenharmony_ci struct usb2phy_reg phy_sus; 14262306a36Sopenharmony_ci struct usb2phy_reg bvalid_det_en; 14362306a36Sopenharmony_ci struct usb2phy_reg bvalid_det_st; 14462306a36Sopenharmony_ci struct usb2phy_reg bvalid_det_clr; 14562306a36Sopenharmony_ci struct usb2phy_reg disfall_en; 14662306a36Sopenharmony_ci struct usb2phy_reg disfall_st; 14762306a36Sopenharmony_ci struct usb2phy_reg disfall_clr; 14862306a36Sopenharmony_ci struct usb2phy_reg disrise_en; 14962306a36Sopenharmony_ci struct usb2phy_reg disrise_st; 15062306a36Sopenharmony_ci struct usb2phy_reg disrise_clr; 15162306a36Sopenharmony_ci struct usb2phy_reg id_det_en; 15262306a36Sopenharmony_ci struct usb2phy_reg id_det_st; 15362306a36Sopenharmony_ci struct usb2phy_reg id_det_clr; 15462306a36Sopenharmony_ci struct usb2phy_reg ls_det_en; 15562306a36Sopenharmony_ci struct usb2phy_reg ls_det_st; 15662306a36Sopenharmony_ci struct usb2phy_reg ls_det_clr; 15762306a36Sopenharmony_ci struct usb2phy_reg utmi_avalid; 15862306a36Sopenharmony_ci struct usb2phy_reg utmi_bvalid; 15962306a36Sopenharmony_ci struct usb2phy_reg utmi_id; 16062306a36Sopenharmony_ci struct usb2phy_reg utmi_ls; 16162306a36Sopenharmony_ci struct usb2phy_reg utmi_hstdet; 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/** 16562306a36Sopenharmony_ci * struct rockchip_usb2phy_cfg - usb-phy configuration. 16662306a36Sopenharmony_ci * @reg: the address offset of grf for usb-phy config. 16762306a36Sopenharmony_ci * @num_ports: specify how many ports that the phy has. 16862306a36Sopenharmony_ci * @phy_tuning: phy default parameters tuning. 16962306a36Sopenharmony_ci * @clkout_ctl: keep on/turn off output clk of phy. 17062306a36Sopenharmony_ci * @port_cfgs: usb-phy port configurations. 17162306a36Sopenharmony_ci * @chg_det: charger detection registers. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_cistruct rockchip_usb2phy_cfg { 17462306a36Sopenharmony_ci unsigned int reg; 17562306a36Sopenharmony_ci unsigned int num_ports; 17662306a36Sopenharmony_ci int (*phy_tuning)(struct rockchip_usb2phy *rphy); 17762306a36Sopenharmony_ci struct usb2phy_reg clkout_ctl; 17862306a36Sopenharmony_ci const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; 17962306a36Sopenharmony_ci const struct rockchip_chg_det_reg chg_det; 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * struct rockchip_usb2phy_port - usb-phy port data. 18462306a36Sopenharmony_ci * @phy: generic phy. 18562306a36Sopenharmony_ci * @port_id: flag for otg port or host port. 18662306a36Sopenharmony_ci * @suspended: phy suspended flag. 18762306a36Sopenharmony_ci * @vbus_attached: otg device vbus status. 18862306a36Sopenharmony_ci * @host_disconnect: usb host disconnect status. 18962306a36Sopenharmony_ci * @bvalid_irq: IRQ number assigned for vbus valid rise detection. 19062306a36Sopenharmony_ci * @id_irq: IRQ number assigned for ID pin detection. 19162306a36Sopenharmony_ci * @ls_irq: IRQ number assigned for linestate detection. 19262306a36Sopenharmony_ci * @otg_mux_irq: IRQ number which multiplex otg-id/otg-bvalid/linestate 19362306a36Sopenharmony_ci * irqs to one irq in otg-port. 19462306a36Sopenharmony_ci * @mutex: for register updating in sm_work. 19562306a36Sopenharmony_ci * @chg_work: charge detect work. 19662306a36Sopenharmony_ci * @otg_sm_work: OTG state machine work. 19762306a36Sopenharmony_ci * @sm_work: HOST state machine work. 19862306a36Sopenharmony_ci * @port_cfg: port register configuration, assigned by driver data. 19962306a36Sopenharmony_ci * @event_nb: hold event notification callback. 20062306a36Sopenharmony_ci * @state: define OTG enumeration states before device reset. 20162306a36Sopenharmony_ci * @mode: the dr_mode of the controller. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistruct rockchip_usb2phy_port { 20462306a36Sopenharmony_ci struct phy *phy; 20562306a36Sopenharmony_ci unsigned int port_id; 20662306a36Sopenharmony_ci bool suspended; 20762306a36Sopenharmony_ci bool vbus_attached; 20862306a36Sopenharmony_ci bool host_disconnect; 20962306a36Sopenharmony_ci int bvalid_irq; 21062306a36Sopenharmony_ci int id_irq; 21162306a36Sopenharmony_ci int ls_irq; 21262306a36Sopenharmony_ci int otg_mux_irq; 21362306a36Sopenharmony_ci struct mutex mutex; 21462306a36Sopenharmony_ci struct delayed_work chg_work; 21562306a36Sopenharmony_ci struct delayed_work otg_sm_work; 21662306a36Sopenharmony_ci struct delayed_work sm_work; 21762306a36Sopenharmony_ci const struct rockchip_usb2phy_port_cfg *port_cfg; 21862306a36Sopenharmony_ci struct notifier_block event_nb; 21962306a36Sopenharmony_ci enum usb_otg_state state; 22062306a36Sopenharmony_ci enum usb_dr_mode mode; 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/** 22462306a36Sopenharmony_ci * struct rockchip_usb2phy - usb2.0 phy driver data. 22562306a36Sopenharmony_ci * @dev: pointer to device. 22662306a36Sopenharmony_ci * @grf: General Register Files regmap. 22762306a36Sopenharmony_ci * @usbgrf: USB General Register Files regmap. 22862306a36Sopenharmony_ci * @clk: clock struct of phy input clk. 22962306a36Sopenharmony_ci * @clk480m: clock struct of phy output clk. 23062306a36Sopenharmony_ci * @clk480m_hw: clock struct of phy output clk management. 23162306a36Sopenharmony_ci * @phy_reset: phy reset control. 23262306a36Sopenharmony_ci * @chg_state: states involved in USB charger detection. 23362306a36Sopenharmony_ci * @chg_type: USB charger types. 23462306a36Sopenharmony_ci * @dcd_retries: The retry count used to track Data contact 23562306a36Sopenharmony_ci * detection process. 23662306a36Sopenharmony_ci * @edev: extcon device for notification registration 23762306a36Sopenharmony_ci * @irq: muxed interrupt for single irq configuration 23862306a36Sopenharmony_ci * @phy_cfg: phy register configuration, assigned by driver data. 23962306a36Sopenharmony_ci * @ports: phy port instance. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_cistruct rockchip_usb2phy { 24262306a36Sopenharmony_ci struct device *dev; 24362306a36Sopenharmony_ci struct regmap *grf; 24462306a36Sopenharmony_ci struct regmap *usbgrf; 24562306a36Sopenharmony_ci struct clk *clk; 24662306a36Sopenharmony_ci struct clk *clk480m; 24762306a36Sopenharmony_ci struct clk_hw clk480m_hw; 24862306a36Sopenharmony_ci struct reset_control *phy_reset; 24962306a36Sopenharmony_ci enum usb_chg_state chg_state; 25062306a36Sopenharmony_ci enum power_supply_type chg_type; 25162306a36Sopenharmony_ci u8 dcd_retries; 25262306a36Sopenharmony_ci struct extcon_dev *edev; 25362306a36Sopenharmony_ci int irq; 25462306a36Sopenharmony_ci const struct rockchip_usb2phy_cfg *phy_cfg; 25562306a36Sopenharmony_ci struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS]; 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic inline struct regmap *get_reg_base(struct rockchip_usb2phy *rphy) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci return rphy->usbgrf == NULL ? rphy->grf : rphy->usbgrf; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic inline int property_enable(struct regmap *base, 26462306a36Sopenharmony_ci const struct usb2phy_reg *reg, bool en) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci unsigned int val, mask, tmp; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci tmp = en ? reg->enable : reg->disable; 26962306a36Sopenharmony_ci mask = GENMASK(reg->bitend, reg->bitstart); 27062306a36Sopenharmony_ci val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return regmap_write(base, reg->offset, val); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic inline bool property_enabled(struct regmap *base, 27662306a36Sopenharmony_ci const struct usb2phy_reg *reg) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci int ret; 27962306a36Sopenharmony_ci unsigned int tmp, orig; 28062306a36Sopenharmony_ci unsigned int mask = GENMASK(reg->bitend, reg->bitstart); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ret = regmap_read(base, reg->offset, &orig); 28362306a36Sopenharmony_ci if (ret) 28462306a36Sopenharmony_ci return false; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci tmp = (orig & mask) >> reg->bitstart; 28762306a36Sopenharmony_ci return tmp != reg->disable; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int rockchip_usb2phy_reset(struct rockchip_usb2phy *rphy) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci int ret; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ret = reset_control_assert(rphy->phy_reset); 29562306a36Sopenharmony_ci if (ret) 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci udelay(10); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ret = reset_control_deassert(rphy->phy_reset); 30162306a36Sopenharmony_ci if (ret) 30262306a36Sopenharmony_ci return ret; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci usleep_range(100, 200); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = 31262306a36Sopenharmony_ci container_of(hw, struct rockchip_usb2phy, clk480m_hw); 31362306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 31462306a36Sopenharmony_ci int ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* turn on 480m clk output if it is off */ 31762306a36Sopenharmony_ci if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { 31862306a36Sopenharmony_ci ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true); 31962306a36Sopenharmony_ci if (ret) 32062306a36Sopenharmony_ci return ret; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* waiting for the clk become stable */ 32362306a36Sopenharmony_ci usleep_range(1200, 1300); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = 33262306a36Sopenharmony_ci container_of(hw, struct rockchip_usb2phy, clk480m_hw); 33362306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* turn off 480m clk output */ 33662306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->clkout_ctl, false); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = 34262306a36Sopenharmony_ci container_of(hw, struct rockchip_usb2phy, clk480m_hw); 34362306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return property_enabled(base, &rphy->phy_cfg->clkout_ctl); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic unsigned long 34962306a36Sopenharmony_cirockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw, 35062306a36Sopenharmony_ci unsigned long parent_rate) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci return 480000000; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic const struct clk_ops rockchip_usb2phy_clkout_ops = { 35662306a36Sopenharmony_ci .prepare = rockchip_usb2phy_clk480m_prepare, 35762306a36Sopenharmony_ci .unprepare = rockchip_usb2phy_clk480m_unprepare, 35862306a36Sopenharmony_ci .is_prepared = rockchip_usb2phy_clk480m_prepared, 35962306a36Sopenharmony_ci .recalc_rate = rockchip_usb2phy_clk480m_recalc_rate, 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void rockchip_usb2phy_clk480m_unregister(void *data) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = data; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci of_clk_del_provider(rphy->dev->of_node); 36762306a36Sopenharmony_ci clk_unregister(rphy->clk480m); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int 37162306a36Sopenharmony_cirockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct device_node *node = rphy->dev->of_node; 37462306a36Sopenharmony_ci struct clk_init_data init; 37562306a36Sopenharmony_ci const char *clk_name; 37662306a36Sopenharmony_ci int ret = 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci init.flags = 0; 37962306a36Sopenharmony_ci init.name = "clk_usbphy_480m"; 38062306a36Sopenharmony_ci init.ops = &rockchip_usb2phy_clkout_ops; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* optional override of the clockname */ 38362306a36Sopenharmony_ci of_property_read_string(node, "clock-output-names", &init.name); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (rphy->clk) { 38662306a36Sopenharmony_ci clk_name = __clk_get_name(rphy->clk); 38762306a36Sopenharmony_ci init.parent_names = &clk_name; 38862306a36Sopenharmony_ci init.num_parents = 1; 38962306a36Sopenharmony_ci } else { 39062306a36Sopenharmony_ci init.parent_names = NULL; 39162306a36Sopenharmony_ci init.num_parents = 0; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci rphy->clk480m_hw.init = &init; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* register the clock */ 39762306a36Sopenharmony_ci rphy->clk480m = clk_register(rphy->dev, &rphy->clk480m_hw); 39862306a36Sopenharmony_ci if (IS_ERR(rphy->clk480m)) { 39962306a36Sopenharmony_ci ret = PTR_ERR(rphy->clk480m); 40062306a36Sopenharmony_ci goto err_ret; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci ret = of_clk_add_provider(node, of_clk_src_simple_get, rphy->clk480m); 40462306a36Sopenharmony_ci if (ret < 0) 40562306a36Sopenharmony_ci goto err_clk_provider; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return devm_add_action_or_reset(rphy->dev, rockchip_usb2phy_clk480m_unregister, rphy); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cierr_clk_provider: 41062306a36Sopenharmony_ci clk_unregister(rphy->clk480m); 41162306a36Sopenharmony_cierr_ret: 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci struct device_node *node = rphy->dev->of_node; 41962306a36Sopenharmony_ci struct extcon_dev *edev; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (of_property_read_bool(node, "extcon")) { 42262306a36Sopenharmony_ci edev = extcon_get_edev_by_phandle(rphy->dev, 0); 42362306a36Sopenharmony_ci if (IS_ERR(edev)) { 42462306a36Sopenharmony_ci if (PTR_ERR(edev) != -EPROBE_DEFER) 42562306a36Sopenharmony_ci dev_err(rphy->dev, "Invalid or missing extcon\n"); 42662306a36Sopenharmony_ci return PTR_ERR(edev); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci } else { 42962306a36Sopenharmony_ci /* Initialize extcon device */ 43062306a36Sopenharmony_ci edev = devm_extcon_dev_allocate(rphy->dev, 43162306a36Sopenharmony_ci rockchip_usb2phy_extcon_cable); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (IS_ERR(edev)) 43462306a36Sopenharmony_ci return -ENOMEM; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci ret = devm_extcon_dev_register(rphy->dev, edev); 43762306a36Sopenharmony_ci if (ret) { 43862306a36Sopenharmony_ci dev_err(rphy->dev, "failed to register extcon device\n"); 43962306a36Sopenharmony_ci return ret; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci rphy->edev = edev; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int rockchip_usb2phy_enable_host_disc_irq(struct rockchip_usb2phy *rphy, 44962306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport, 45062306a36Sopenharmony_ci bool en) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci int ret; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ret = property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true); 45562306a36Sopenharmony_ci if (ret) 45662306a36Sopenharmony_ci return ret; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ret = property_enable(rphy->grf, &rport->port_cfg->disfall_en, en); 45962306a36Sopenharmony_ci if (ret) 46062306a36Sopenharmony_ci return ret; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci ret = property_enable(rphy->grf, &rport->port_cfg->disrise_clr, true); 46362306a36Sopenharmony_ci if (ret) 46462306a36Sopenharmony_ci return ret; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return property_enable(rphy->grf, &rport->port_cfg->disrise_en, en); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int rockchip_usb2phy_init(struct phy *phy) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); 47262306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); 47362306a36Sopenharmony_ci int ret = 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci mutex_lock(&rport->mutex); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (rport->port_id == USB2PHY_PORT_OTG) { 47862306a36Sopenharmony_ci if (rport->mode != USB_DR_MODE_HOST && 47962306a36Sopenharmony_ci rport->mode != USB_DR_MODE_UNKNOWN) { 48062306a36Sopenharmony_ci /* clear bvalid status and enable bvalid detect irq */ 48162306a36Sopenharmony_ci ret = property_enable(rphy->grf, 48262306a36Sopenharmony_ci &rport->port_cfg->bvalid_det_clr, 48362306a36Sopenharmony_ci true); 48462306a36Sopenharmony_ci if (ret) 48562306a36Sopenharmony_ci goto out; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ret = property_enable(rphy->grf, 48862306a36Sopenharmony_ci &rport->port_cfg->bvalid_det_en, 48962306a36Sopenharmony_ci true); 49062306a36Sopenharmony_ci if (ret) 49162306a36Sopenharmony_ci goto out; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* clear id status and enable id detect irq */ 49462306a36Sopenharmony_ci ret = property_enable(rphy->grf, 49562306a36Sopenharmony_ci &rport->port_cfg->id_det_clr, 49662306a36Sopenharmony_ci true); 49762306a36Sopenharmony_ci if (ret) 49862306a36Sopenharmony_ci goto out; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci ret = property_enable(rphy->grf, 50162306a36Sopenharmony_ci &rport->port_cfg->id_det_en, 50262306a36Sopenharmony_ci true); 50362306a36Sopenharmony_ci if (ret) 50462306a36Sopenharmony_ci goto out; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci schedule_delayed_work(&rport->otg_sm_work, 50762306a36Sopenharmony_ci OTG_SCHEDULE_DELAY * 3); 50862306a36Sopenharmony_ci } else { 50962306a36Sopenharmony_ci /* If OTG works in host only mode, do nothing. */ 51062306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci } else if (rport->port_id == USB2PHY_PORT_HOST) { 51362306a36Sopenharmony_ci if (rport->port_cfg->disfall_en.offset) { 51462306a36Sopenharmony_ci rport->host_disconnect = true; 51562306a36Sopenharmony_ci ret = rockchip_usb2phy_enable_host_disc_irq(rphy, rport, true); 51662306a36Sopenharmony_ci if (ret) { 51762306a36Sopenharmony_ci dev_err(rphy->dev, "failed to enable disconnect irq\n"); 51862306a36Sopenharmony_ci goto out; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* clear linestate and enable linestate detect irq */ 52362306a36Sopenharmony_ci ret = property_enable(rphy->grf, 52462306a36Sopenharmony_ci &rport->port_cfg->ls_det_clr, true); 52562306a36Sopenharmony_ci if (ret) 52662306a36Sopenharmony_ci goto out; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ret = property_enable(rphy->grf, 52962306a36Sopenharmony_ci &rport->port_cfg->ls_det_en, true); 53062306a36Sopenharmony_ci if (ret) 53162306a36Sopenharmony_ci goto out; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ciout: 53762306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int rockchip_usb2phy_power_on(struct phy *phy) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); 54462306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); 54562306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 54662306a36Sopenharmony_ci int ret; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "port power on\n"); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!rport->suspended) 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci ret = clk_prepare_enable(rphy->clk480m); 55462306a36Sopenharmony_ci if (ret) 55562306a36Sopenharmony_ci return ret; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci ret = property_enable(base, &rport->port_cfg->phy_sus, false); 55862306a36Sopenharmony_ci if (ret) { 55962306a36Sopenharmony_ci clk_disable_unprepare(rphy->clk480m); 56062306a36Sopenharmony_ci return ret; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* 56462306a36Sopenharmony_ci * For rk3588, it needs to reset phy when exit from 56562306a36Sopenharmony_ci * suspend mode with common_on_n 1'b1(aka REFCLK_LOGIC, 56662306a36Sopenharmony_ci * Bias, and PLL blocks are powered down) for lower 56762306a36Sopenharmony_ci * power consumption. If you don't want to reset phy, 56862306a36Sopenharmony_ci * please keep the common_on_n 1'b0 to set these blocks 56962306a36Sopenharmony_ci * remain powered. 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_ci ret = rockchip_usb2phy_reset(rphy); 57262306a36Sopenharmony_ci if (ret) 57362306a36Sopenharmony_ci return ret; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* waiting for the utmi_clk to become stable */ 57662306a36Sopenharmony_ci usleep_range(1500, 2000); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci rport->suspended = false; 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int rockchip_usb2phy_power_off(struct phy *phy) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); 58562306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); 58662306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 58762306a36Sopenharmony_ci int ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "port power off\n"); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (rport->suspended) 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci ret = property_enable(base, &rport->port_cfg->phy_sus, true); 59562306a36Sopenharmony_ci if (ret) 59662306a36Sopenharmony_ci return ret; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci rport->suspended = true; 59962306a36Sopenharmony_ci clk_disable_unprepare(rphy->clk480m); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int rockchip_usb2phy_exit(struct phy *phy) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (rport->port_id == USB2PHY_PORT_OTG && 60962306a36Sopenharmony_ci rport->mode != USB_DR_MODE_HOST && 61062306a36Sopenharmony_ci rport->mode != USB_DR_MODE_UNKNOWN) { 61162306a36Sopenharmony_ci cancel_delayed_work_sync(&rport->otg_sm_work); 61262306a36Sopenharmony_ci cancel_delayed_work_sync(&rport->chg_work); 61362306a36Sopenharmony_ci } else if (rport->port_id == USB2PHY_PORT_HOST) 61462306a36Sopenharmony_ci cancel_delayed_work_sync(&rport->sm_work); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return 0; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic const struct phy_ops rockchip_usb2phy_ops = { 62062306a36Sopenharmony_ci .init = rockchip_usb2phy_init, 62162306a36Sopenharmony_ci .exit = rockchip_usb2phy_exit, 62262306a36Sopenharmony_ci .power_on = rockchip_usb2phy_power_on, 62362306a36Sopenharmony_ci .power_off = rockchip_usb2phy_power_off, 62462306a36Sopenharmony_ci .owner = THIS_MODULE, 62562306a36Sopenharmony_ci}; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void rockchip_usb2phy_otg_sm_work(struct work_struct *work) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = 63062306a36Sopenharmony_ci container_of(work, struct rockchip_usb2phy_port, 63162306a36Sopenharmony_ci otg_sm_work.work); 63262306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 63362306a36Sopenharmony_ci static unsigned int cable; 63462306a36Sopenharmony_ci unsigned long delay; 63562306a36Sopenharmony_ci bool vbus_attach, sch_work, notify_charger; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci vbus_attach = property_enabled(rphy->grf, 63862306a36Sopenharmony_ci &rport->port_cfg->utmi_bvalid); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci sch_work = false; 64162306a36Sopenharmony_ci notify_charger = false; 64262306a36Sopenharmony_ci delay = OTG_SCHEDULE_DELAY; 64362306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "%s otg sm work\n", 64462306a36Sopenharmony_ci usb_otg_state_string(rport->state)); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci switch (rport->state) { 64762306a36Sopenharmony_ci case OTG_STATE_UNDEFINED: 64862306a36Sopenharmony_ci rport->state = OTG_STATE_B_IDLE; 64962306a36Sopenharmony_ci if (!vbus_attach) 65062306a36Sopenharmony_ci rockchip_usb2phy_power_off(rport->phy); 65162306a36Sopenharmony_ci fallthrough; 65262306a36Sopenharmony_ci case OTG_STATE_B_IDLE: 65362306a36Sopenharmony_ci if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) { 65462306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "usb otg host connect\n"); 65562306a36Sopenharmony_ci rport->state = OTG_STATE_A_HOST; 65662306a36Sopenharmony_ci rockchip_usb2phy_power_on(rport->phy); 65762306a36Sopenharmony_ci return; 65862306a36Sopenharmony_ci } else if (vbus_attach) { 65962306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "vbus_attach\n"); 66062306a36Sopenharmony_ci switch (rphy->chg_state) { 66162306a36Sopenharmony_ci case USB_CHG_STATE_UNDEFINED: 66262306a36Sopenharmony_ci schedule_delayed_work(&rport->chg_work, 0); 66362306a36Sopenharmony_ci return; 66462306a36Sopenharmony_ci case USB_CHG_STATE_DETECTED: 66562306a36Sopenharmony_ci switch (rphy->chg_type) { 66662306a36Sopenharmony_ci case POWER_SUPPLY_TYPE_USB: 66762306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "sdp cable is connected\n"); 66862306a36Sopenharmony_ci rockchip_usb2phy_power_on(rport->phy); 66962306a36Sopenharmony_ci rport->state = OTG_STATE_B_PERIPHERAL; 67062306a36Sopenharmony_ci notify_charger = true; 67162306a36Sopenharmony_ci sch_work = true; 67262306a36Sopenharmony_ci cable = EXTCON_CHG_USB_SDP; 67362306a36Sopenharmony_ci break; 67462306a36Sopenharmony_ci case POWER_SUPPLY_TYPE_USB_DCP: 67562306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "dcp cable is connected\n"); 67662306a36Sopenharmony_ci rockchip_usb2phy_power_off(rport->phy); 67762306a36Sopenharmony_ci notify_charger = true; 67862306a36Sopenharmony_ci sch_work = true; 67962306a36Sopenharmony_ci cable = EXTCON_CHG_USB_DCP; 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci case POWER_SUPPLY_TYPE_USB_CDP: 68262306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "cdp cable is connected\n"); 68362306a36Sopenharmony_ci rockchip_usb2phy_power_on(rport->phy); 68462306a36Sopenharmony_ci rport->state = OTG_STATE_B_PERIPHERAL; 68562306a36Sopenharmony_ci notify_charger = true; 68662306a36Sopenharmony_ci sch_work = true; 68762306a36Sopenharmony_ci cable = EXTCON_CHG_USB_CDP; 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci default: 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci default: 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci } else { 69762306a36Sopenharmony_ci notify_charger = true; 69862306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_UNDEFINED; 69962306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (rport->vbus_attached != vbus_attach) { 70362306a36Sopenharmony_ci rport->vbus_attached = vbus_attach; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (notify_charger && rphy->edev) { 70662306a36Sopenharmony_ci extcon_set_state_sync(rphy->edev, 70762306a36Sopenharmony_ci cable, vbus_attach); 70862306a36Sopenharmony_ci if (cable == EXTCON_CHG_USB_SDP) 70962306a36Sopenharmony_ci extcon_set_state_sync(rphy->edev, 71062306a36Sopenharmony_ci EXTCON_USB, 71162306a36Sopenharmony_ci vbus_attach); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci case OTG_STATE_B_PERIPHERAL: 71662306a36Sopenharmony_ci if (!vbus_attach) { 71762306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "usb disconnect\n"); 71862306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_UNDEFINED; 71962306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; 72062306a36Sopenharmony_ci rport->state = OTG_STATE_B_IDLE; 72162306a36Sopenharmony_ci delay = 0; 72262306a36Sopenharmony_ci rockchip_usb2phy_power_off(rport->phy); 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci sch_work = true; 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci case OTG_STATE_A_HOST: 72762306a36Sopenharmony_ci if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) { 72862306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "usb otg host disconnect\n"); 72962306a36Sopenharmony_ci rport->state = OTG_STATE_B_IDLE; 73062306a36Sopenharmony_ci rockchip_usb2phy_power_off(rport->phy); 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci default: 73462306a36Sopenharmony_ci break; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (sch_work) 73862306a36Sopenharmony_ci schedule_delayed_work(&rport->otg_sm_work, delay); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic const char *chg_to_string(enum power_supply_type chg_type) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci switch (chg_type) { 74462306a36Sopenharmony_ci case POWER_SUPPLY_TYPE_USB: 74562306a36Sopenharmony_ci return "USB_SDP_CHARGER"; 74662306a36Sopenharmony_ci case POWER_SUPPLY_TYPE_USB_DCP: 74762306a36Sopenharmony_ci return "USB_DCP_CHARGER"; 74862306a36Sopenharmony_ci case POWER_SUPPLY_TYPE_USB_CDP: 74962306a36Sopenharmony_ci return "USB_CDP_CHARGER"; 75062306a36Sopenharmony_ci default: 75162306a36Sopenharmony_ci return "INVALID_CHARGER"; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy, 75662306a36Sopenharmony_ci bool en) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en); 76162306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.idp_src_en, en); 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy, 76562306a36Sopenharmony_ci bool en) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.vdp_src_en, en); 77062306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.idm_sink_en, en); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy, 77462306a36Sopenharmony_ci bool en) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.vdm_src_en, en); 77962306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.idp_sink_en, en); 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci#define CHG_DCD_POLL_TIME (100 * HZ / 1000) 78362306a36Sopenharmony_ci#define CHG_DCD_MAX_RETRIES 6 78462306a36Sopenharmony_ci#define CHG_PRIMARY_DET_TIME (40 * HZ / 1000) 78562306a36Sopenharmony_ci#define CHG_SECONDARY_DET_TIME (40 * HZ / 1000) 78662306a36Sopenharmony_cistatic void rockchip_chg_detect_work(struct work_struct *work) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = 78962306a36Sopenharmony_ci container_of(work, struct rockchip_usb2phy_port, chg_work.work); 79062306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 79162306a36Sopenharmony_ci struct regmap *base = get_reg_base(rphy); 79262306a36Sopenharmony_ci bool is_dcd, tmout, vout; 79362306a36Sopenharmony_ci unsigned long delay; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "chg detection work state = %d\n", 79662306a36Sopenharmony_ci rphy->chg_state); 79762306a36Sopenharmony_ci switch (rphy->chg_state) { 79862306a36Sopenharmony_ci case USB_CHG_STATE_UNDEFINED: 79962306a36Sopenharmony_ci if (!rport->suspended) 80062306a36Sopenharmony_ci rockchip_usb2phy_power_off(rport->phy); 80162306a36Sopenharmony_ci /* put the controller in non-driving mode */ 80262306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); 80362306a36Sopenharmony_ci /* Start DCD processing stage 1 */ 80462306a36Sopenharmony_ci rockchip_chg_enable_dcd(rphy, true); 80562306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; 80662306a36Sopenharmony_ci rphy->dcd_retries = 0; 80762306a36Sopenharmony_ci delay = CHG_DCD_POLL_TIME; 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci case USB_CHG_STATE_WAIT_FOR_DCD: 81062306a36Sopenharmony_ci /* get data contact detection status */ 81162306a36Sopenharmony_ci is_dcd = property_enabled(rphy->grf, 81262306a36Sopenharmony_ci &rphy->phy_cfg->chg_det.dp_det); 81362306a36Sopenharmony_ci tmout = ++rphy->dcd_retries == CHG_DCD_MAX_RETRIES; 81462306a36Sopenharmony_ci /* stage 2 */ 81562306a36Sopenharmony_ci if (is_dcd || tmout) { 81662306a36Sopenharmony_ci /* stage 4 */ 81762306a36Sopenharmony_ci /* Turn off DCD circuitry */ 81862306a36Sopenharmony_ci rockchip_chg_enable_dcd(rphy, false); 81962306a36Sopenharmony_ci /* Voltage Source on DP, Probe on DM */ 82062306a36Sopenharmony_ci rockchip_chg_enable_primary_det(rphy, true); 82162306a36Sopenharmony_ci delay = CHG_PRIMARY_DET_TIME; 82262306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_DCD_DONE; 82362306a36Sopenharmony_ci } else { 82462306a36Sopenharmony_ci /* stage 3 */ 82562306a36Sopenharmony_ci delay = CHG_DCD_POLL_TIME; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci case USB_CHG_STATE_DCD_DONE: 82962306a36Sopenharmony_ci vout = property_enabled(rphy->grf, 83062306a36Sopenharmony_ci &rphy->phy_cfg->chg_det.cp_det); 83162306a36Sopenharmony_ci rockchip_chg_enable_primary_det(rphy, false); 83262306a36Sopenharmony_ci if (vout) { 83362306a36Sopenharmony_ci /* Voltage Source on DM, Probe on DP */ 83462306a36Sopenharmony_ci rockchip_chg_enable_secondary_det(rphy, true); 83562306a36Sopenharmony_ci delay = CHG_SECONDARY_DET_TIME; 83662306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_PRIMARY_DONE; 83762306a36Sopenharmony_ci } else { 83862306a36Sopenharmony_ci if (rphy->dcd_retries == CHG_DCD_MAX_RETRIES) { 83962306a36Sopenharmony_ci /* floating charger found */ 84062306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP; 84162306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_DETECTED; 84262306a36Sopenharmony_ci delay = 0; 84362306a36Sopenharmony_ci } else { 84462306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_USB; 84562306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_DETECTED; 84662306a36Sopenharmony_ci delay = 0; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci break; 85062306a36Sopenharmony_ci case USB_CHG_STATE_PRIMARY_DONE: 85162306a36Sopenharmony_ci vout = property_enabled(rphy->grf, 85262306a36Sopenharmony_ci &rphy->phy_cfg->chg_det.dcp_det); 85362306a36Sopenharmony_ci /* Turn off voltage source */ 85462306a36Sopenharmony_ci rockchip_chg_enable_secondary_det(rphy, false); 85562306a36Sopenharmony_ci if (vout) 85662306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_USB_DCP; 85762306a36Sopenharmony_ci else 85862306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_USB_CDP; 85962306a36Sopenharmony_ci fallthrough; 86062306a36Sopenharmony_ci case USB_CHG_STATE_SECONDARY_DONE: 86162306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_DETECTED; 86262306a36Sopenharmony_ci fallthrough; 86362306a36Sopenharmony_ci case USB_CHG_STATE_DETECTED: 86462306a36Sopenharmony_ci /* put the controller in normal mode */ 86562306a36Sopenharmony_ci property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); 86662306a36Sopenharmony_ci rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work); 86762306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "charger = %s\n", 86862306a36Sopenharmony_ci chg_to_string(rphy->chg_type)); 86962306a36Sopenharmony_ci return; 87062306a36Sopenharmony_ci default: 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci schedule_delayed_work(&rport->chg_work, delay); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/* 87862306a36Sopenharmony_ci * The function manage host-phy port state and suspend/resume phy port 87962306a36Sopenharmony_ci * to save power. 88062306a36Sopenharmony_ci * 88162306a36Sopenharmony_ci * we rely on utmi_linestate and utmi_hostdisconnect to identify whether 88262306a36Sopenharmony_ci * devices is disconnect or not. Besides, we do not need care it is FS/LS 88362306a36Sopenharmony_ci * disconnected or HS disconnected, actually, we just only need get the 88462306a36Sopenharmony_ci * device is disconnected at last through rearm the delayed work, 88562306a36Sopenharmony_ci * to suspend the phy port in _PHY_STATE_DISCONNECT_ case. 88662306a36Sopenharmony_ci * 88762306a36Sopenharmony_ci * NOTE: It may invoke *phy_powr_off or *phy_power_on which will invoke 88862306a36Sopenharmony_ci * some clk related APIs, so do not invoke it from interrupt context directly. 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_cistatic void rockchip_usb2phy_sm_work(struct work_struct *work) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = 89362306a36Sopenharmony_ci container_of(work, struct rockchip_usb2phy_port, sm_work.work); 89462306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 89562306a36Sopenharmony_ci unsigned int sh, ul, uhd, state; 89662306a36Sopenharmony_ci unsigned int ul_mask, uhd_mask; 89762306a36Sopenharmony_ci int ret; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci mutex_lock(&rport->mutex); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul); 90262306a36Sopenharmony_ci if (ret < 0) 90362306a36Sopenharmony_ci goto next_schedule; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend, 90662306a36Sopenharmony_ci rport->port_cfg->utmi_ls.bitstart); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (rport->port_cfg->utmi_hstdet.offset) { 90962306a36Sopenharmony_ci ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd); 91062306a36Sopenharmony_ci if (ret < 0) 91162306a36Sopenharmony_ci goto next_schedule; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend, 91462306a36Sopenharmony_ci rport->port_cfg->utmi_hstdet.bitstart); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci sh = rport->port_cfg->utmi_hstdet.bitend - 91762306a36Sopenharmony_ci rport->port_cfg->utmi_hstdet.bitstart + 1; 91862306a36Sopenharmony_ci /* stitch on utmi_ls and utmi_hstdet as phy state */ 91962306a36Sopenharmony_ci state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) | 92062306a36Sopenharmony_ci (((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh); 92162306a36Sopenharmony_ci } else { 92262306a36Sopenharmony_ci state = ((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << 1 | 92362306a36Sopenharmony_ci rport->host_disconnect; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci switch (state) { 92762306a36Sopenharmony_ci case PHY_STATE_HS_ONLINE: 92862306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "HS online\n"); 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci case PHY_STATE_FS_LS_ONLINE: 93162306a36Sopenharmony_ci /* 93262306a36Sopenharmony_ci * For FS/LS device, the online state share with connect state 93362306a36Sopenharmony_ci * from utmi_ls and utmi_hstdet register, so we distinguish 93462306a36Sopenharmony_ci * them via suspended flag. 93562306a36Sopenharmony_ci * 93662306a36Sopenharmony_ci * Plus, there are two cases, one is D- Line pull-up, and D+ 93762306a36Sopenharmony_ci * line pull-down, the state is 4; another is D+ line pull-up, 93862306a36Sopenharmony_ci * and D- line pull-down, the state is 2. 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci if (!rport->suspended) { 94162306a36Sopenharmony_ci /* D- line pull-up, D+ line pull-down */ 94262306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "FS/LS online\n"); 94362306a36Sopenharmony_ci break; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci fallthrough; 94662306a36Sopenharmony_ci case PHY_STATE_CONNECT: 94762306a36Sopenharmony_ci if (rport->suspended) { 94862306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "Connected\n"); 94962306a36Sopenharmony_ci rockchip_usb2phy_power_on(rport->phy); 95062306a36Sopenharmony_ci rport->suspended = false; 95162306a36Sopenharmony_ci } else { 95262306a36Sopenharmony_ci /* D+ line pull-up, D- line pull-down */ 95362306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "FS/LS online\n"); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci break; 95662306a36Sopenharmony_ci case PHY_STATE_DISCONNECT: 95762306a36Sopenharmony_ci if (!rport->suspended) { 95862306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "Disconnected\n"); 95962306a36Sopenharmony_ci rockchip_usb2phy_power_off(rport->phy); 96062306a36Sopenharmony_ci rport->suspended = true; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* 96462306a36Sopenharmony_ci * activate the linestate detection to get the next device 96562306a36Sopenharmony_ci * plug-in irq. 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true); 96862306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->ls_det_en, true); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* 97162306a36Sopenharmony_ci * we don't need to rearm the delayed work when the phy port 97262306a36Sopenharmony_ci * is suspended. 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 97562306a36Sopenharmony_ci return; 97662306a36Sopenharmony_ci default: 97762306a36Sopenharmony_ci dev_dbg(&rport->phy->dev, "unknown phy state\n"); 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cinext_schedule: 98262306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 98362306a36Sopenharmony_ci schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = data; 98962306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (!property_enabled(rphy->grf, &rport->port_cfg->ls_det_st)) 99262306a36Sopenharmony_ci return IRQ_NONE; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci mutex_lock(&rport->mutex); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* disable linestate detect irq and clear its status */ 99762306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->ls_det_en, false); 99862306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci /* 100362306a36Sopenharmony_ci * In this case for host phy port, a new device is plugged in, 100462306a36Sopenharmony_ci * meanwhile, if the phy port is suspended, we need rearm the work to 100562306a36Sopenharmony_ci * resume it and mange its states; otherwise, we do nothing about that. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST) 100862306a36Sopenharmony_ci rockchip_usb2phy_sm_work(&rport->sm_work.work); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return IRQ_HANDLED; 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = data; 101662306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (!property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st)) 101962306a36Sopenharmony_ci return IRQ_NONE; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* clear bvalid detect irq pending status */ 102262306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->bvalid_det_clr, true); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci return IRQ_HANDLED; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic irqreturn_t rockchip_usb2phy_id_irq(int irq, void *data) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = data; 103262306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 103362306a36Sopenharmony_ci bool id; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (!property_enabled(rphy->grf, &rport->port_cfg->id_det_st)) 103662306a36Sopenharmony_ci return IRQ_NONE; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci /* clear id detect irq pending status */ 103962306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->id_det_clr, true); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id); 104262306a36Sopenharmony_ci extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci return IRQ_HANDLED; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci ret |= rockchip_usb2phy_bvalid_irq(irq, data); 105262306a36Sopenharmony_ci ret |= rockchip_usb2phy_id_irq(irq, data); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return ret; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic irqreturn_t rockchip_usb2phy_host_disc_irq(int irq, void *data) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = data; 106062306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (!property_enabled(rphy->grf, &rport->port_cfg->disfall_st) && 106362306a36Sopenharmony_ci !property_enabled(rphy->grf, &rport->port_cfg->disrise_st)) 106462306a36Sopenharmony_ci return IRQ_NONE; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci mutex_lock(&rport->mutex); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* clear disconnect fall or rise detect irq pending status */ 106962306a36Sopenharmony_ci if (property_enabled(rphy->grf, &rport->port_cfg->disfall_st)) { 107062306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true); 107162306a36Sopenharmony_ci rport->host_disconnect = false; 107262306a36Sopenharmony_ci } else if (property_enabled(rphy->grf, &rport->port_cfg->disrise_st)) { 107362306a36Sopenharmony_ci property_enable(rphy->grf, &rport->port_cfg->disrise_clr, true); 107462306a36Sopenharmony_ci rport->host_disconnect = true; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci mutex_unlock(&rport->mutex); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci return IRQ_HANDLED; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic irqreturn_t rockchip_usb2phy_irq(int irq, void *data) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci struct rockchip_usb2phy *rphy = data; 108562306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport; 108662306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 108762306a36Sopenharmony_ci unsigned int index; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci for (index = 0; index < rphy->phy_cfg->num_ports; index++) { 109062306a36Sopenharmony_ci rport = &rphy->ports[index]; 109162306a36Sopenharmony_ci if (!rport->phy) 109262306a36Sopenharmony_ci continue; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (rport->port_id == USB2PHY_PORT_HOST && 109562306a36Sopenharmony_ci rport->port_cfg->disfall_en.offset) 109662306a36Sopenharmony_ci ret |= rockchip_usb2phy_host_disc_irq(irq, rport); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci switch (rport->port_id) { 109962306a36Sopenharmony_ci case USB2PHY_PORT_OTG: 110062306a36Sopenharmony_ci if (rport->mode != USB_DR_MODE_HOST && 110162306a36Sopenharmony_ci rport->mode != USB_DR_MODE_UNKNOWN) 110262306a36Sopenharmony_ci ret |= rockchip_usb2phy_otg_mux_irq(irq, rport); 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci case USB2PHY_PORT_HOST: 110562306a36Sopenharmony_ci ret |= rockchip_usb2phy_linestate_irq(irq, rport); 110662306a36Sopenharmony_ci break; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return ret; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int rockchip_usb2phy_port_irq_init(struct rockchip_usb2phy *rphy, 111462306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport, 111562306a36Sopenharmony_ci struct device_node *child_np) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci int ret; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci /* 112062306a36Sopenharmony_ci * If the usb2 phy used combined irq for otg and host port, 112162306a36Sopenharmony_ci * don't need to init otg and host port irq separately. 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_ci if (rphy->irq > 0) 112462306a36Sopenharmony_ci return 0; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci switch (rport->port_id) { 112762306a36Sopenharmony_ci case USB2PHY_PORT_HOST: 112862306a36Sopenharmony_ci rport->ls_irq = of_irq_get_byname(child_np, "linestate"); 112962306a36Sopenharmony_ci if (rport->ls_irq < 0) { 113062306a36Sopenharmony_ci dev_err(rphy->dev, "no linestate irq provided\n"); 113162306a36Sopenharmony_ci return rport->ls_irq; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL, 113562306a36Sopenharmony_ci rockchip_usb2phy_linestate_irq, 113662306a36Sopenharmony_ci IRQF_ONESHOT, 113762306a36Sopenharmony_ci "rockchip_usb2phy", rport); 113862306a36Sopenharmony_ci if (ret) { 113962306a36Sopenharmony_ci dev_err(rphy->dev, "failed to request linestate irq handle\n"); 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci case USB2PHY_PORT_OTG: 114462306a36Sopenharmony_ci /* 114562306a36Sopenharmony_ci * Some SoCs use one interrupt with otg-id/otg-bvalid/linestate 114662306a36Sopenharmony_ci * interrupts muxed together, so probe the otg-mux interrupt first, 114762306a36Sopenharmony_ci * if not found, then look for the regular interrupts one by one. 114862306a36Sopenharmony_ci */ 114962306a36Sopenharmony_ci rport->otg_mux_irq = of_irq_get_byname(child_np, "otg-mux"); 115062306a36Sopenharmony_ci if (rport->otg_mux_irq > 0) { 115162306a36Sopenharmony_ci ret = devm_request_threaded_irq(rphy->dev, rport->otg_mux_irq, 115262306a36Sopenharmony_ci NULL, 115362306a36Sopenharmony_ci rockchip_usb2phy_otg_mux_irq, 115462306a36Sopenharmony_ci IRQF_ONESHOT, 115562306a36Sopenharmony_ci "rockchip_usb2phy_otg", 115662306a36Sopenharmony_ci rport); 115762306a36Sopenharmony_ci if (ret) { 115862306a36Sopenharmony_ci dev_err(rphy->dev, 115962306a36Sopenharmony_ci "failed to request otg-mux irq handle\n"); 116062306a36Sopenharmony_ci return ret; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci } else { 116362306a36Sopenharmony_ci rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid"); 116462306a36Sopenharmony_ci if (rport->bvalid_irq < 0) { 116562306a36Sopenharmony_ci dev_err(rphy->dev, "no vbus valid irq provided\n"); 116662306a36Sopenharmony_ci ret = rport->bvalid_irq; 116762306a36Sopenharmony_ci return ret; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq, 117162306a36Sopenharmony_ci NULL, 117262306a36Sopenharmony_ci rockchip_usb2phy_bvalid_irq, 117362306a36Sopenharmony_ci IRQF_ONESHOT, 117462306a36Sopenharmony_ci "rockchip_usb2phy_bvalid", 117562306a36Sopenharmony_ci rport); 117662306a36Sopenharmony_ci if (ret) { 117762306a36Sopenharmony_ci dev_err(rphy->dev, 117862306a36Sopenharmony_ci "failed to request otg-bvalid irq handle\n"); 117962306a36Sopenharmony_ci return ret; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci rport->id_irq = of_irq_get_byname(child_np, "otg-id"); 118362306a36Sopenharmony_ci if (rport->id_irq < 0) { 118462306a36Sopenharmony_ci dev_err(rphy->dev, "no otg-id irq provided\n"); 118562306a36Sopenharmony_ci ret = rport->id_irq; 118662306a36Sopenharmony_ci return ret; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci ret = devm_request_threaded_irq(rphy->dev, rport->id_irq, 119062306a36Sopenharmony_ci NULL, 119162306a36Sopenharmony_ci rockchip_usb2phy_id_irq, 119262306a36Sopenharmony_ci IRQF_ONESHOT, 119362306a36Sopenharmony_ci "rockchip_usb2phy_id", 119462306a36Sopenharmony_ci rport); 119562306a36Sopenharmony_ci if (ret) { 119662306a36Sopenharmony_ci dev_err(rphy->dev, 119762306a36Sopenharmony_ci "failed to request otg-id irq handle\n"); 119862306a36Sopenharmony_ci return ret; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci default: 120362306a36Sopenharmony_ci return -EINVAL; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return 0; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy, 121062306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport, 121162306a36Sopenharmony_ci struct device_node *child_np) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci int ret; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci rport->port_id = USB2PHY_PORT_HOST; 121662306a36Sopenharmony_ci rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST]; 121762306a36Sopenharmony_ci rport->suspended = true; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci mutex_init(&rport->mutex); 122062306a36Sopenharmony_ci INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np); 122362306a36Sopenharmony_ci if (ret) { 122462306a36Sopenharmony_ci dev_err(rphy->dev, "failed to setup host irq\n"); 122562306a36Sopenharmony_ci return ret; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int rockchip_otg_event(struct notifier_block *nb, 123262306a36Sopenharmony_ci unsigned long event, void *ptr) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = 123562306a36Sopenharmony_ci container_of(nb, struct rockchip_usb2phy_port, event_nb); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci schedule_delayed_work(&rport->otg_sm_work, OTG_SCHEDULE_DELAY); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci return NOTIFY_DONE; 124062306a36Sopenharmony_ci} 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, 124362306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport, 124462306a36Sopenharmony_ci struct device_node *child_np) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci int ret, id; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci rport->port_id = USB2PHY_PORT_OTG; 124962306a36Sopenharmony_ci rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG]; 125062306a36Sopenharmony_ci rport->state = OTG_STATE_UNDEFINED; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* 125362306a36Sopenharmony_ci * set suspended flag to true, but actually don't 125462306a36Sopenharmony_ci * put phy in suspend mode, it aims to enable usb 125562306a36Sopenharmony_ci * phy and clock in power_on() called by usb controller 125662306a36Sopenharmony_ci * driver during probe. 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_ci rport->suspended = true; 125962306a36Sopenharmony_ci rport->vbus_attached = false; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci mutex_init(&rport->mutex); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1); 126462306a36Sopenharmony_ci if (rport->mode == USB_DR_MODE_HOST || 126562306a36Sopenharmony_ci rport->mode == USB_DR_MODE_UNKNOWN) { 126662306a36Sopenharmony_ci ret = 0; 126762306a36Sopenharmony_ci goto out; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work); 127162306a36Sopenharmony_ci INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci ret = rockchip_usb2phy_port_irq_init(rphy, rport, child_np); 127462306a36Sopenharmony_ci if (ret) { 127562306a36Sopenharmony_ci dev_err(rphy->dev, "failed to init irq for host port\n"); 127662306a36Sopenharmony_ci goto out; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (!IS_ERR(rphy->edev)) { 128062306a36Sopenharmony_ci rport->event_nb.notifier_call = rockchip_otg_event; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci ret = devm_extcon_register_notifier(rphy->dev, rphy->edev, 128362306a36Sopenharmony_ci EXTCON_USB_HOST, &rport->event_nb); 128462306a36Sopenharmony_ci if (ret) { 128562306a36Sopenharmony_ci dev_err(rphy->dev, "register USB HOST notifier failed\n"); 128662306a36Sopenharmony_ci goto out; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci if (!of_property_read_bool(rphy->dev->of_node, "extcon")) { 129062306a36Sopenharmony_ci /* do initial sync of usb state */ 129162306a36Sopenharmony_ci id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id); 129262306a36Sopenharmony_ci extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ciout: 129762306a36Sopenharmony_ci return ret; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int rockchip_usb2phy_probe(struct platform_device *pdev) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 130362306a36Sopenharmony_ci struct device_node *np = dev->of_node; 130462306a36Sopenharmony_ci struct device_node *child_np; 130562306a36Sopenharmony_ci struct phy_provider *provider; 130662306a36Sopenharmony_ci struct rockchip_usb2phy *rphy; 130762306a36Sopenharmony_ci const struct rockchip_usb2phy_cfg *phy_cfgs; 130862306a36Sopenharmony_ci unsigned int reg; 130962306a36Sopenharmony_ci int index, ret; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); 131262306a36Sopenharmony_ci if (!rphy) 131362306a36Sopenharmony_ci return -ENOMEM; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (!dev->parent || !dev->parent->of_node) { 131662306a36Sopenharmony_ci rphy->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbgrf"); 131762306a36Sopenharmony_ci if (IS_ERR(rphy->grf)) { 131862306a36Sopenharmony_ci dev_err(dev, "failed to locate usbgrf\n"); 131962306a36Sopenharmony_ci return PTR_ERR(rphy->grf); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci else { 132462306a36Sopenharmony_ci rphy->grf = syscon_node_to_regmap(dev->parent->of_node); 132562306a36Sopenharmony_ci if (IS_ERR(rphy->grf)) 132662306a36Sopenharmony_ci return PTR_ERR(rphy->grf); 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (of_device_is_compatible(np, "rockchip,rv1108-usb2phy")) { 133062306a36Sopenharmony_ci rphy->usbgrf = 133162306a36Sopenharmony_ci syscon_regmap_lookup_by_phandle(dev->of_node, 133262306a36Sopenharmony_ci "rockchip,usbgrf"); 133362306a36Sopenharmony_ci if (IS_ERR(rphy->usbgrf)) 133462306a36Sopenharmony_ci return PTR_ERR(rphy->usbgrf); 133562306a36Sopenharmony_ci } else { 133662306a36Sopenharmony_ci rphy->usbgrf = NULL; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci if (of_property_read_u32_index(np, "reg", 0, ®)) { 134062306a36Sopenharmony_ci dev_err(dev, "the reg property is not assigned in %pOFn node\n", 134162306a36Sopenharmony_ci np); 134262306a36Sopenharmony_ci return -EINVAL; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci /* support address_cells=2 */ 134662306a36Sopenharmony_ci if (of_property_count_u32_elems(np, "reg") > 2 && reg == 0) { 134762306a36Sopenharmony_ci if (of_property_read_u32_index(np, "reg", 1, ®)) { 134862306a36Sopenharmony_ci dev_err(dev, "the reg property is not assigned in %pOFn node\n", 134962306a36Sopenharmony_ci np); 135062306a36Sopenharmony_ci return -EINVAL; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci rphy->dev = dev; 135562306a36Sopenharmony_ci phy_cfgs = device_get_match_data(dev); 135662306a36Sopenharmony_ci rphy->chg_state = USB_CHG_STATE_UNDEFINED; 135762306a36Sopenharmony_ci rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; 135862306a36Sopenharmony_ci rphy->irq = platform_get_irq_optional(pdev, 0); 135962306a36Sopenharmony_ci platform_set_drvdata(pdev, rphy); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (!phy_cfgs) 136262306a36Sopenharmony_ci return dev_err_probe(dev, -EINVAL, "phy configs are not assigned!\n"); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci ret = rockchip_usb2phy_extcon_register(rphy); 136562306a36Sopenharmony_ci if (ret) 136662306a36Sopenharmony_ci return ret; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci /* find out a proper config which can be matched with dt. */ 136962306a36Sopenharmony_ci index = 0; 137062306a36Sopenharmony_ci do { 137162306a36Sopenharmony_ci if (phy_cfgs[index].reg == reg) { 137262306a36Sopenharmony_ci rphy->phy_cfg = &phy_cfgs[index]; 137362306a36Sopenharmony_ci break; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci ++index; 137762306a36Sopenharmony_ci } while (phy_cfgs[index].reg); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (!rphy->phy_cfg) { 138062306a36Sopenharmony_ci dev_err(dev, "could not find phy config for reg=0x%08x\n", reg); 138162306a36Sopenharmony_ci return -EINVAL; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci rphy->phy_reset = devm_reset_control_get_optional(dev, "phy"); 138562306a36Sopenharmony_ci if (IS_ERR(rphy->phy_reset)) 138662306a36Sopenharmony_ci return PTR_ERR(rphy->phy_reset); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci rphy->clk = devm_clk_get_optional_enabled(dev, "phyclk"); 138962306a36Sopenharmony_ci if (IS_ERR(rphy->clk)) { 139062306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(rphy->clk), 139162306a36Sopenharmony_ci "failed to get phyclk\n"); 139262306a36Sopenharmony_ci } 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci ret = rockchip_usb2phy_clk480m_register(rphy); 139562306a36Sopenharmony_ci if (ret) { 139662306a36Sopenharmony_ci dev_err(dev, "failed to register 480m output clock\n"); 139762306a36Sopenharmony_ci return ret; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (rphy->phy_cfg->phy_tuning) { 140162306a36Sopenharmony_ci ret = rphy->phy_cfg->phy_tuning(rphy); 140262306a36Sopenharmony_ci if (ret) 140362306a36Sopenharmony_ci return ret; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci index = 0; 140762306a36Sopenharmony_ci for_each_available_child_of_node(np, child_np) { 140862306a36Sopenharmony_ci struct rockchip_usb2phy_port *rport = &rphy->ports[index]; 140962306a36Sopenharmony_ci struct phy *phy; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* This driver aims to support both otg-port and host-port */ 141262306a36Sopenharmony_ci if (!of_node_name_eq(child_np, "host-port") && 141362306a36Sopenharmony_ci !of_node_name_eq(child_np, "otg-port")) 141462306a36Sopenharmony_ci goto next_child; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); 141762306a36Sopenharmony_ci if (IS_ERR(phy)) { 141862306a36Sopenharmony_ci dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); 141962306a36Sopenharmony_ci ret = PTR_ERR(phy); 142062306a36Sopenharmony_ci goto put_child; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci rport->phy = phy; 142462306a36Sopenharmony_ci phy_set_drvdata(rport->phy, rport); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci /* initialize otg/host port separately */ 142762306a36Sopenharmony_ci if (of_node_name_eq(child_np, "host-port")) { 142862306a36Sopenharmony_ci ret = rockchip_usb2phy_host_port_init(rphy, rport, 142962306a36Sopenharmony_ci child_np); 143062306a36Sopenharmony_ci if (ret) 143162306a36Sopenharmony_ci goto put_child; 143262306a36Sopenharmony_ci } else { 143362306a36Sopenharmony_ci ret = rockchip_usb2phy_otg_port_init(rphy, rport, 143462306a36Sopenharmony_ci child_np); 143562306a36Sopenharmony_ci if (ret) 143662306a36Sopenharmony_ci goto put_child; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cinext_child: 144062306a36Sopenharmony_ci /* to prevent out of boundary */ 144162306a36Sopenharmony_ci if (++index >= rphy->phy_cfg->num_ports) { 144262306a36Sopenharmony_ci of_node_put(child_np); 144362306a36Sopenharmony_ci break; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (rphy->irq > 0) { 145062306a36Sopenharmony_ci ret = devm_request_threaded_irq(rphy->dev, rphy->irq, NULL, 145162306a36Sopenharmony_ci rockchip_usb2phy_irq, 145262306a36Sopenharmony_ci IRQF_ONESHOT, 145362306a36Sopenharmony_ci "rockchip_usb2phy", 145462306a36Sopenharmony_ci rphy); 145562306a36Sopenharmony_ci if (ret) { 145662306a36Sopenharmony_ci dev_err(rphy->dev, 145762306a36Sopenharmony_ci "failed to request usb2phy irq handle\n"); 145862306a36Sopenharmony_ci goto put_child; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(provider); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ciput_child: 146562306a36Sopenharmony_ci of_node_put(child_np); 146662306a36Sopenharmony_ci return ret; 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cistatic int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci int ret; 147262306a36Sopenharmony_ci bool usb3otg = false; 147362306a36Sopenharmony_ci /* 147462306a36Sopenharmony_ci * utmi_termselect = 1'b1 (en FS terminations) 147562306a36Sopenharmony_ci * utmi_xcvrselect = 2'b01 (FS transceiver) 147662306a36Sopenharmony_ci */ 147762306a36Sopenharmony_ci int suspend_cfg = 0x14; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci if (rphy->phy_cfg->reg == 0x0000 || rphy->phy_cfg->reg == 0x4000) { 148062306a36Sopenharmony_ci /* USB2 config for USB3_0 and USB3_1 */ 148162306a36Sopenharmony_ci suspend_cfg |= 0x01; /* utmi_opmode = 2'b01 (no-driving) */ 148262306a36Sopenharmony_ci usb3otg = true; 148362306a36Sopenharmony_ci } else if (rphy->phy_cfg->reg == 0x8000 || rphy->phy_cfg->reg == 0xc000) { 148462306a36Sopenharmony_ci /* USB2 config for USB2_0 and USB2_1 */ 148562306a36Sopenharmony_ci suspend_cfg |= 0x00; /* utmi_opmode = 2'b00 (normal) */ 148662306a36Sopenharmony_ci } else { 148762306a36Sopenharmony_ci return -EINVAL; 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci /* Deassert SIDDQ to power on analog block */ 149162306a36Sopenharmony_ci ret = regmap_write(rphy->grf, 0x0008, GENMASK(29, 29) | 0x0000); 149262306a36Sopenharmony_ci if (ret) 149362306a36Sopenharmony_ci return ret; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci /* Do reset after exit IDDQ mode */ 149662306a36Sopenharmony_ci ret = rockchip_usb2phy_reset(rphy); 149762306a36Sopenharmony_ci if (ret) 149862306a36Sopenharmony_ci return ret; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci /* suspend configuration */ 150162306a36Sopenharmony_ci ret |= regmap_write(rphy->grf, 0x000c, GENMASK(20, 16) | suspend_cfg); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* HS DC Voltage Level Adjustment 4'b1001 : +5.89% */ 150462306a36Sopenharmony_ci ret |= regmap_write(rphy->grf, 0x0004, GENMASK(27, 24) | 0x0900); 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* HS Transmitter Pre-Emphasis Current Control 2'b10 : 2x */ 150762306a36Sopenharmony_ci ret |= regmap_write(rphy->grf, 0x0008, GENMASK(20, 19) | 0x0010); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (!usb3otg) 151062306a36Sopenharmony_ci return ret; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci /* Pullup iddig pin for USB3_0 OTG mode */ 151362306a36Sopenharmony_ci ret |= regmap_write(rphy->grf, 0x0010, GENMASK(17, 16) | 0x0003); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci return ret; 151662306a36Sopenharmony_ci} 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = { 151962306a36Sopenharmony_ci { 152062306a36Sopenharmony_ci .reg = 0x760, 152162306a36Sopenharmony_ci .num_ports = 2, 152262306a36Sopenharmony_ci .clkout_ctl = { 0x0768, 4, 4, 1, 0 }, 152362306a36Sopenharmony_ci .port_cfgs = { 152462306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 152562306a36Sopenharmony_ci .phy_sus = { 0x0760, 15, 0, 0, 0x1d1 }, 152662306a36Sopenharmony_ci .bvalid_det_en = { 0x0680, 3, 3, 0, 1 }, 152762306a36Sopenharmony_ci .bvalid_det_st = { 0x0690, 3, 3, 0, 1 }, 152862306a36Sopenharmony_ci .bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 }, 152962306a36Sopenharmony_ci .id_det_en = { 0x0680, 6, 5, 0, 3 }, 153062306a36Sopenharmony_ci .id_det_st = { 0x0690, 6, 5, 0, 3 }, 153162306a36Sopenharmony_ci .id_det_clr = { 0x06a0, 6, 5, 0, 3 }, 153262306a36Sopenharmony_ci .ls_det_en = { 0x0680, 2, 2, 0, 1 }, 153362306a36Sopenharmony_ci .ls_det_st = { 0x0690, 2, 2, 0, 1 }, 153462306a36Sopenharmony_ci .ls_det_clr = { 0x06a0, 2, 2, 0, 1 }, 153562306a36Sopenharmony_ci .utmi_bvalid = { 0x0480, 4, 4, 0, 1 }, 153662306a36Sopenharmony_ci .utmi_id = { 0x0480, 1, 1, 0, 1 }, 153762306a36Sopenharmony_ci .utmi_ls = { 0x0480, 3, 2, 0, 1 }, 153862306a36Sopenharmony_ci }, 153962306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 154062306a36Sopenharmony_ci .phy_sus = { 0x0764, 15, 0, 0, 0x1d1 }, 154162306a36Sopenharmony_ci .ls_det_en = { 0x0680, 4, 4, 0, 1 }, 154262306a36Sopenharmony_ci .ls_det_st = { 0x0690, 4, 4, 0, 1 }, 154362306a36Sopenharmony_ci .ls_det_clr = { 0x06a0, 4, 4, 0, 1 } 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci }, 154662306a36Sopenharmony_ci .chg_det = { 154762306a36Sopenharmony_ci .opmode = { 0x0760, 3, 0, 5, 1 }, 154862306a36Sopenharmony_ci .cp_det = { 0x0884, 4, 4, 0, 1 }, 154962306a36Sopenharmony_ci .dcp_det = { 0x0884, 3, 3, 0, 1 }, 155062306a36Sopenharmony_ci .dp_det = { 0x0884, 5, 5, 0, 1 }, 155162306a36Sopenharmony_ci .idm_sink_en = { 0x0768, 8, 8, 0, 1 }, 155262306a36Sopenharmony_ci .idp_sink_en = { 0x0768, 7, 7, 0, 1 }, 155362306a36Sopenharmony_ci .idp_src_en = { 0x0768, 9, 9, 0, 1 }, 155462306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0768, 10, 10, 0, 1 }, 155562306a36Sopenharmony_ci .vdm_src_en = { 0x0768, 12, 12, 0, 1 }, 155662306a36Sopenharmony_ci .vdp_src_en = { 0x0768, 11, 11, 0, 1 }, 155762306a36Sopenharmony_ci }, 155862306a36Sopenharmony_ci }, 155962306a36Sopenharmony_ci { 156062306a36Sopenharmony_ci .reg = 0x800, 156162306a36Sopenharmony_ci .num_ports = 2, 156262306a36Sopenharmony_ci .clkout_ctl = { 0x0808, 4, 4, 1, 0 }, 156362306a36Sopenharmony_ci .port_cfgs = { 156462306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 156562306a36Sopenharmony_ci .phy_sus = { 0x800, 15, 0, 0, 0x1d1 }, 156662306a36Sopenharmony_ci .ls_det_en = { 0x0684, 0, 0, 0, 1 }, 156762306a36Sopenharmony_ci .ls_det_st = { 0x0694, 0, 0, 0, 1 }, 156862306a36Sopenharmony_ci .ls_det_clr = { 0x06a4, 0, 0, 0, 1 } 156962306a36Sopenharmony_ci }, 157062306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 157162306a36Sopenharmony_ci .phy_sus = { 0x804, 15, 0, 0, 0x1d1 }, 157262306a36Sopenharmony_ci .ls_det_en = { 0x0684, 1, 1, 0, 1 }, 157362306a36Sopenharmony_ci .ls_det_st = { 0x0694, 1, 1, 0, 1 }, 157462306a36Sopenharmony_ci .ls_det_clr = { 0x06a4, 1, 1, 0, 1 } 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci }, 157762306a36Sopenharmony_ci }, 157862306a36Sopenharmony_ci { /* sentinel */ } 157962306a36Sopenharmony_ci}; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3308_phy_cfgs[] = { 158262306a36Sopenharmony_ci { 158362306a36Sopenharmony_ci .reg = 0x100, 158462306a36Sopenharmony_ci .num_ports = 2, 158562306a36Sopenharmony_ci .clkout_ctl = { 0x108, 4, 4, 1, 0 }, 158662306a36Sopenharmony_ci .port_cfgs = { 158762306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 158862306a36Sopenharmony_ci .phy_sus = { 0x0100, 8, 0, 0, 0x1d1 }, 158962306a36Sopenharmony_ci .bvalid_det_en = { 0x3020, 3, 2, 0, 3 }, 159062306a36Sopenharmony_ci .bvalid_det_st = { 0x3024, 3, 2, 0, 3 }, 159162306a36Sopenharmony_ci .bvalid_det_clr = { 0x3028, 3, 2, 0, 3 }, 159262306a36Sopenharmony_ci .id_det_en = { 0x3020, 5, 4, 0, 3 }, 159362306a36Sopenharmony_ci .id_det_st = { 0x3024, 5, 4, 0, 3 }, 159462306a36Sopenharmony_ci .id_det_clr = { 0x3028, 5, 4, 0, 3 }, 159562306a36Sopenharmony_ci .ls_det_en = { 0x3020, 0, 0, 0, 1 }, 159662306a36Sopenharmony_ci .ls_det_st = { 0x3024, 0, 0, 0, 1 }, 159762306a36Sopenharmony_ci .ls_det_clr = { 0x3028, 0, 0, 0, 1 }, 159862306a36Sopenharmony_ci .utmi_avalid = { 0x0120, 10, 10, 0, 1 }, 159962306a36Sopenharmony_ci .utmi_bvalid = { 0x0120, 9, 9, 0, 1 }, 160062306a36Sopenharmony_ci .utmi_id = { 0x0120, 6, 6, 0, 1 }, 160162306a36Sopenharmony_ci .utmi_ls = { 0x0120, 5, 4, 0, 1 }, 160262306a36Sopenharmony_ci }, 160362306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 160462306a36Sopenharmony_ci .phy_sus = { 0x0104, 8, 0, 0, 0x1d1 }, 160562306a36Sopenharmony_ci .ls_det_en = { 0x3020, 1, 1, 0, 1 }, 160662306a36Sopenharmony_ci .ls_det_st = { 0x3024, 1, 1, 0, 1 }, 160762306a36Sopenharmony_ci .ls_det_clr = { 0x3028, 1, 1, 0, 1 }, 160862306a36Sopenharmony_ci .utmi_ls = { 0x0120, 17, 16, 0, 1 }, 160962306a36Sopenharmony_ci .utmi_hstdet = { 0x0120, 19, 19, 0, 1 } 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci }, 161262306a36Sopenharmony_ci .chg_det = { 161362306a36Sopenharmony_ci .opmode = { 0x0100, 3, 0, 5, 1 }, 161462306a36Sopenharmony_ci .cp_det = { 0x0120, 24, 24, 0, 1 }, 161562306a36Sopenharmony_ci .dcp_det = { 0x0120, 23, 23, 0, 1 }, 161662306a36Sopenharmony_ci .dp_det = { 0x0120, 25, 25, 0, 1 }, 161762306a36Sopenharmony_ci .idm_sink_en = { 0x0108, 8, 8, 0, 1 }, 161862306a36Sopenharmony_ci .idp_sink_en = { 0x0108, 7, 7, 0, 1 }, 161962306a36Sopenharmony_ci .idp_src_en = { 0x0108, 9, 9, 0, 1 }, 162062306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 }, 162162306a36Sopenharmony_ci .vdm_src_en = { 0x0108, 12, 12, 0, 1 }, 162262306a36Sopenharmony_ci .vdp_src_en = { 0x0108, 11, 11, 0, 1 }, 162362306a36Sopenharmony_ci }, 162462306a36Sopenharmony_ci }, 162562306a36Sopenharmony_ci { /* sentinel */ } 162662306a36Sopenharmony_ci}; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = { 162962306a36Sopenharmony_ci { 163062306a36Sopenharmony_ci .reg = 0x100, 163162306a36Sopenharmony_ci .num_ports = 2, 163262306a36Sopenharmony_ci .clkout_ctl = { 0x108, 4, 4, 1, 0 }, 163362306a36Sopenharmony_ci .port_cfgs = { 163462306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 163562306a36Sopenharmony_ci .phy_sus = { 0x0100, 15, 0, 0, 0x1d1 }, 163662306a36Sopenharmony_ci .bvalid_det_en = { 0x0110, 3, 2, 0, 3 }, 163762306a36Sopenharmony_ci .bvalid_det_st = { 0x0114, 3, 2, 0, 3 }, 163862306a36Sopenharmony_ci .bvalid_det_clr = { 0x0118, 3, 2, 0, 3 }, 163962306a36Sopenharmony_ci .id_det_en = { 0x0110, 5, 4, 0, 3 }, 164062306a36Sopenharmony_ci .id_det_st = { 0x0114, 5, 4, 0, 3 }, 164162306a36Sopenharmony_ci .id_det_clr = { 0x0118, 5, 4, 0, 3 }, 164262306a36Sopenharmony_ci .ls_det_en = { 0x0110, 0, 0, 0, 1 }, 164362306a36Sopenharmony_ci .ls_det_st = { 0x0114, 0, 0, 0, 1 }, 164462306a36Sopenharmony_ci .ls_det_clr = { 0x0118, 0, 0, 0, 1 }, 164562306a36Sopenharmony_ci .utmi_avalid = { 0x0120, 10, 10, 0, 1 }, 164662306a36Sopenharmony_ci .utmi_bvalid = { 0x0120, 9, 9, 0, 1 }, 164762306a36Sopenharmony_ci .utmi_id = { 0x0120, 6, 6, 0, 1 }, 164862306a36Sopenharmony_ci .utmi_ls = { 0x0120, 5, 4, 0, 1 }, 164962306a36Sopenharmony_ci }, 165062306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 165162306a36Sopenharmony_ci .phy_sus = { 0x104, 15, 0, 0, 0x1d1 }, 165262306a36Sopenharmony_ci .ls_det_en = { 0x110, 1, 1, 0, 1 }, 165362306a36Sopenharmony_ci .ls_det_st = { 0x114, 1, 1, 0, 1 }, 165462306a36Sopenharmony_ci .ls_det_clr = { 0x118, 1, 1, 0, 1 }, 165562306a36Sopenharmony_ci .utmi_ls = { 0x120, 17, 16, 0, 1 }, 165662306a36Sopenharmony_ci .utmi_hstdet = { 0x120, 19, 19, 0, 1 } 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci }, 165962306a36Sopenharmony_ci .chg_det = { 166062306a36Sopenharmony_ci .opmode = { 0x0100, 3, 0, 5, 1 }, 166162306a36Sopenharmony_ci .cp_det = { 0x0120, 24, 24, 0, 1 }, 166262306a36Sopenharmony_ci .dcp_det = { 0x0120, 23, 23, 0, 1 }, 166362306a36Sopenharmony_ci .dp_det = { 0x0120, 25, 25, 0, 1 }, 166462306a36Sopenharmony_ci .idm_sink_en = { 0x0108, 8, 8, 0, 1 }, 166562306a36Sopenharmony_ci .idp_sink_en = { 0x0108, 7, 7, 0, 1 }, 166662306a36Sopenharmony_ci .idp_src_en = { 0x0108, 9, 9, 0, 1 }, 166762306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 }, 166862306a36Sopenharmony_ci .vdm_src_en = { 0x0108, 12, 12, 0, 1 }, 166962306a36Sopenharmony_ci .vdp_src_en = { 0x0108, 11, 11, 0, 1 }, 167062306a36Sopenharmony_ci }, 167162306a36Sopenharmony_ci }, 167262306a36Sopenharmony_ci { /* sentinel */ } 167362306a36Sopenharmony_ci}; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = { 167662306a36Sopenharmony_ci { 167762306a36Sopenharmony_ci .reg = 0x700, 167862306a36Sopenharmony_ci .num_ports = 2, 167962306a36Sopenharmony_ci .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, 168062306a36Sopenharmony_ci .port_cfgs = { 168162306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 168262306a36Sopenharmony_ci .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, 168362306a36Sopenharmony_ci .ls_det_en = { 0x0680, 4, 4, 0, 1 }, 168462306a36Sopenharmony_ci .ls_det_st = { 0x0690, 4, 4, 0, 1 }, 168562306a36Sopenharmony_ci .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, 168662306a36Sopenharmony_ci .utmi_ls = { 0x049c, 14, 13, 0, 1 }, 168762306a36Sopenharmony_ci .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci }, 169062306a36Sopenharmony_ci }, 169162306a36Sopenharmony_ci { /* sentinel */ } 169262306a36Sopenharmony_ci}; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { 169562306a36Sopenharmony_ci { 169662306a36Sopenharmony_ci .reg = 0xe450, 169762306a36Sopenharmony_ci .num_ports = 2, 169862306a36Sopenharmony_ci .clkout_ctl = { 0xe450, 4, 4, 1, 0 }, 169962306a36Sopenharmony_ci .port_cfgs = { 170062306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 170162306a36Sopenharmony_ci .phy_sus = { 0xe454, 1, 0, 2, 1 }, 170262306a36Sopenharmony_ci .bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 }, 170362306a36Sopenharmony_ci .bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 }, 170462306a36Sopenharmony_ci .bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 }, 170562306a36Sopenharmony_ci .id_det_en = { 0xe3c0, 5, 4, 0, 3 }, 170662306a36Sopenharmony_ci .id_det_st = { 0xe3e0, 5, 4, 0, 3 }, 170762306a36Sopenharmony_ci .id_det_clr = { 0xe3d0, 5, 4, 0, 3 }, 170862306a36Sopenharmony_ci .utmi_avalid = { 0xe2ac, 7, 7, 0, 1 }, 170962306a36Sopenharmony_ci .utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 }, 171062306a36Sopenharmony_ci .utmi_id = { 0xe2ac, 8, 8, 0, 1 }, 171162306a36Sopenharmony_ci }, 171262306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 171362306a36Sopenharmony_ci .phy_sus = { 0xe458, 1, 0, 0x2, 0x1 }, 171462306a36Sopenharmony_ci .ls_det_en = { 0xe3c0, 6, 6, 0, 1 }, 171562306a36Sopenharmony_ci .ls_det_st = { 0xe3e0, 6, 6, 0, 1 }, 171662306a36Sopenharmony_ci .ls_det_clr = { 0xe3d0, 6, 6, 0, 1 }, 171762306a36Sopenharmony_ci .utmi_ls = { 0xe2ac, 22, 21, 0, 1 }, 171862306a36Sopenharmony_ci .utmi_hstdet = { 0xe2ac, 23, 23, 0, 1 } 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci }, 172162306a36Sopenharmony_ci .chg_det = { 172262306a36Sopenharmony_ci .opmode = { 0xe454, 3, 0, 5, 1 }, 172362306a36Sopenharmony_ci .cp_det = { 0xe2ac, 2, 2, 0, 1 }, 172462306a36Sopenharmony_ci .dcp_det = { 0xe2ac, 1, 1, 0, 1 }, 172562306a36Sopenharmony_ci .dp_det = { 0xe2ac, 0, 0, 0, 1 }, 172662306a36Sopenharmony_ci .idm_sink_en = { 0xe450, 8, 8, 0, 1 }, 172762306a36Sopenharmony_ci .idp_sink_en = { 0xe450, 7, 7, 0, 1 }, 172862306a36Sopenharmony_ci .idp_src_en = { 0xe450, 9, 9, 0, 1 }, 172962306a36Sopenharmony_ci .rdm_pdwn_en = { 0xe450, 10, 10, 0, 1 }, 173062306a36Sopenharmony_ci .vdm_src_en = { 0xe450, 12, 12, 0, 1 }, 173162306a36Sopenharmony_ci .vdp_src_en = { 0xe450, 11, 11, 0, 1 }, 173262306a36Sopenharmony_ci }, 173362306a36Sopenharmony_ci }, 173462306a36Sopenharmony_ci { 173562306a36Sopenharmony_ci .reg = 0xe460, 173662306a36Sopenharmony_ci .num_ports = 2, 173762306a36Sopenharmony_ci .clkout_ctl = { 0xe460, 4, 4, 1, 0 }, 173862306a36Sopenharmony_ci .port_cfgs = { 173962306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 174062306a36Sopenharmony_ci .phy_sus = { 0xe464, 1, 0, 2, 1 }, 174162306a36Sopenharmony_ci .bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 }, 174262306a36Sopenharmony_ci .bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 }, 174362306a36Sopenharmony_ci .bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 }, 174462306a36Sopenharmony_ci .id_det_en = { 0xe3c0, 10, 9, 0, 3 }, 174562306a36Sopenharmony_ci .id_det_st = { 0xe3e0, 10, 9, 0, 3 }, 174662306a36Sopenharmony_ci .id_det_clr = { 0xe3d0, 10, 9, 0, 3 }, 174762306a36Sopenharmony_ci .utmi_avalid = { 0xe2ac, 10, 10, 0, 1 }, 174862306a36Sopenharmony_ci .utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 }, 174962306a36Sopenharmony_ci .utmi_id = { 0xe2ac, 11, 11, 0, 1 }, 175062306a36Sopenharmony_ci }, 175162306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 175262306a36Sopenharmony_ci .phy_sus = { 0xe468, 1, 0, 0x2, 0x1 }, 175362306a36Sopenharmony_ci .ls_det_en = { 0xe3c0, 11, 11, 0, 1 }, 175462306a36Sopenharmony_ci .ls_det_st = { 0xe3e0, 11, 11, 0, 1 }, 175562306a36Sopenharmony_ci .ls_det_clr = { 0xe3d0, 11, 11, 0, 1 }, 175662306a36Sopenharmony_ci .utmi_ls = { 0xe2ac, 26, 25, 0, 1 }, 175762306a36Sopenharmony_ci .utmi_hstdet = { 0xe2ac, 27, 27, 0, 1 } 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci }, 176062306a36Sopenharmony_ci }, 176162306a36Sopenharmony_ci { /* sentinel */ } 176262306a36Sopenharmony_ci}; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { 176562306a36Sopenharmony_ci { 176662306a36Sopenharmony_ci .reg = 0xfe8a0000, 176762306a36Sopenharmony_ci .num_ports = 2, 176862306a36Sopenharmony_ci .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, 176962306a36Sopenharmony_ci .port_cfgs = { 177062306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 177162306a36Sopenharmony_ci .phy_sus = { 0x0000, 8, 0, 0, 0x1d1 }, 177262306a36Sopenharmony_ci .bvalid_det_en = { 0x0080, 3, 2, 0, 3 }, 177362306a36Sopenharmony_ci .bvalid_det_st = { 0x0084, 3, 2, 0, 3 }, 177462306a36Sopenharmony_ci .bvalid_det_clr = { 0x0088, 3, 2, 0, 3 }, 177562306a36Sopenharmony_ci .id_det_en = { 0x0080, 5, 4, 0, 3 }, 177662306a36Sopenharmony_ci .id_det_st = { 0x0084, 5, 4, 0, 3 }, 177762306a36Sopenharmony_ci .id_det_clr = { 0x0088, 5, 4, 0, 3 }, 177862306a36Sopenharmony_ci .utmi_avalid = { 0x00c0, 10, 10, 0, 1 }, 177962306a36Sopenharmony_ci .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 }, 178062306a36Sopenharmony_ci .utmi_id = { 0x00c0, 6, 6, 0, 1 }, 178162306a36Sopenharmony_ci }, 178262306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 178362306a36Sopenharmony_ci /* Select suspend control from controller */ 178462306a36Sopenharmony_ci .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d2 }, 178562306a36Sopenharmony_ci .ls_det_en = { 0x0080, 1, 1, 0, 1 }, 178662306a36Sopenharmony_ci .ls_det_st = { 0x0084, 1, 1, 0, 1 }, 178762306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 1, 1, 0, 1 }, 178862306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 17, 16, 0, 1 }, 178962306a36Sopenharmony_ci .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 } 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci }, 179262306a36Sopenharmony_ci .chg_det = { 179362306a36Sopenharmony_ci .opmode = { 0x0000, 3, 0, 5, 1 }, 179462306a36Sopenharmony_ci .cp_det = { 0x00c0, 24, 24, 0, 1 }, 179562306a36Sopenharmony_ci .dcp_det = { 0x00c0, 23, 23, 0, 1 }, 179662306a36Sopenharmony_ci .dp_det = { 0x00c0, 25, 25, 0, 1 }, 179762306a36Sopenharmony_ci .idm_sink_en = { 0x0008, 8, 8, 0, 1 }, 179862306a36Sopenharmony_ci .idp_sink_en = { 0x0008, 7, 7, 0, 1 }, 179962306a36Sopenharmony_ci .idp_src_en = { 0x0008, 9, 9, 0, 1 }, 180062306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0008, 10, 10, 0, 1 }, 180162306a36Sopenharmony_ci .vdm_src_en = { 0x0008, 12, 12, 0, 1 }, 180262306a36Sopenharmony_ci .vdp_src_en = { 0x0008, 11, 11, 0, 1 }, 180362306a36Sopenharmony_ci }, 180462306a36Sopenharmony_ci }, 180562306a36Sopenharmony_ci { 180662306a36Sopenharmony_ci .reg = 0xfe8b0000, 180762306a36Sopenharmony_ci .num_ports = 2, 180862306a36Sopenharmony_ci .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, 180962306a36Sopenharmony_ci .port_cfgs = { 181062306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 181162306a36Sopenharmony_ci .phy_sus = { 0x0000, 8, 0, 0x1d2, 0x1d1 }, 181262306a36Sopenharmony_ci .ls_det_en = { 0x0080, 0, 0, 0, 1 }, 181362306a36Sopenharmony_ci .ls_det_st = { 0x0084, 0, 0, 0, 1 }, 181462306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, 181562306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 5, 4, 0, 1 }, 181662306a36Sopenharmony_ci .utmi_hstdet = { 0x00c0, 7, 7, 0, 1 } 181762306a36Sopenharmony_ci }, 181862306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 181962306a36Sopenharmony_ci .phy_sus = { 0x0004, 8, 0, 0x1d2, 0x1d1 }, 182062306a36Sopenharmony_ci .ls_det_en = { 0x0080, 1, 1, 0, 1 }, 182162306a36Sopenharmony_ci .ls_det_st = { 0x0084, 1, 1, 0, 1 }, 182262306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 1, 1, 0, 1 }, 182362306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 17, 16, 0, 1 }, 182462306a36Sopenharmony_ci .utmi_hstdet = { 0x00c0, 19, 19, 0, 1 } 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci }, 182762306a36Sopenharmony_ci }, 182862306a36Sopenharmony_ci { /* sentinel */ } 182962306a36Sopenharmony_ci}; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { 183262306a36Sopenharmony_ci { 183362306a36Sopenharmony_ci .reg = 0x0000, 183462306a36Sopenharmony_ci .num_ports = 1, 183562306a36Sopenharmony_ci .phy_tuning = rk3588_usb2phy_tuning, 183662306a36Sopenharmony_ci .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, 183762306a36Sopenharmony_ci .port_cfgs = { 183862306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 183962306a36Sopenharmony_ci .phy_sus = { 0x000c, 11, 11, 0, 1 }, 184062306a36Sopenharmony_ci .bvalid_det_en = { 0x0080, 1, 1, 0, 1 }, 184162306a36Sopenharmony_ci .bvalid_det_st = { 0x0084, 1, 1, 0, 1 }, 184262306a36Sopenharmony_ci .bvalid_det_clr = { 0x0088, 1, 1, 0, 1 }, 184362306a36Sopenharmony_ci .ls_det_en = { 0x0080, 0, 0, 0, 1 }, 184462306a36Sopenharmony_ci .ls_det_st = { 0x0084, 0, 0, 0, 1 }, 184562306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, 184662306a36Sopenharmony_ci .disfall_en = { 0x0080, 6, 6, 0, 1 }, 184762306a36Sopenharmony_ci .disfall_st = { 0x0084, 6, 6, 0, 1 }, 184862306a36Sopenharmony_ci .disfall_clr = { 0x0088, 6, 6, 0, 1 }, 184962306a36Sopenharmony_ci .disrise_en = { 0x0080, 5, 5, 0, 1 }, 185062306a36Sopenharmony_ci .disrise_st = { 0x0084, 5, 5, 0, 1 }, 185162306a36Sopenharmony_ci .disrise_clr = { 0x0088, 5, 5, 0, 1 }, 185262306a36Sopenharmony_ci .utmi_avalid = { 0x00c0, 7, 7, 0, 1 }, 185362306a36Sopenharmony_ci .utmi_bvalid = { 0x00c0, 6, 6, 0, 1 }, 185462306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci }, 185762306a36Sopenharmony_ci .chg_det = { 185862306a36Sopenharmony_ci .cp_det = { 0x00c0, 0, 0, 0, 1 }, 185962306a36Sopenharmony_ci .dcp_det = { 0x00c0, 0, 0, 0, 1 }, 186062306a36Sopenharmony_ci .dp_det = { 0x00c0, 1, 1, 1, 0 }, 186162306a36Sopenharmony_ci .idm_sink_en = { 0x0008, 5, 5, 1, 0 }, 186262306a36Sopenharmony_ci .idp_sink_en = { 0x0008, 5, 5, 0, 1 }, 186362306a36Sopenharmony_ci .idp_src_en = { 0x0008, 14, 14, 0, 1 }, 186462306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0008, 14, 14, 0, 1 }, 186562306a36Sopenharmony_ci .vdm_src_en = { 0x0008, 7, 6, 0, 3 }, 186662306a36Sopenharmony_ci .vdp_src_en = { 0x0008, 7, 6, 0, 3 }, 186762306a36Sopenharmony_ci }, 186862306a36Sopenharmony_ci }, 186962306a36Sopenharmony_ci { 187062306a36Sopenharmony_ci .reg = 0x4000, 187162306a36Sopenharmony_ci .num_ports = 1, 187262306a36Sopenharmony_ci .phy_tuning = rk3588_usb2phy_tuning, 187362306a36Sopenharmony_ci .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, 187462306a36Sopenharmony_ci .port_cfgs = { 187562306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 187662306a36Sopenharmony_ci .phy_sus = { 0x000c, 11, 11, 0, 1 }, 187762306a36Sopenharmony_ci .bvalid_det_en = { 0x0080, 1, 1, 0, 1 }, 187862306a36Sopenharmony_ci .bvalid_det_st = { 0x0084, 1, 1, 0, 1 }, 187962306a36Sopenharmony_ci .bvalid_det_clr = { 0x0088, 1, 1, 0, 1 }, 188062306a36Sopenharmony_ci .ls_det_en = { 0x0080, 0, 0, 0, 1 }, 188162306a36Sopenharmony_ci .ls_det_st = { 0x0084, 0, 0, 0, 1 }, 188262306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, 188362306a36Sopenharmony_ci .disfall_en = { 0x0080, 6, 6, 0, 1 }, 188462306a36Sopenharmony_ci .disfall_st = { 0x0084, 6, 6, 0, 1 }, 188562306a36Sopenharmony_ci .disfall_clr = { 0x0088, 6, 6, 0, 1 }, 188662306a36Sopenharmony_ci .disrise_en = { 0x0080, 5, 5, 0, 1 }, 188762306a36Sopenharmony_ci .disrise_st = { 0x0084, 5, 5, 0, 1 }, 188862306a36Sopenharmony_ci .disrise_clr = { 0x0088, 5, 5, 0, 1 }, 188962306a36Sopenharmony_ci .utmi_avalid = { 0x00c0, 7, 7, 0, 1 }, 189062306a36Sopenharmony_ci .utmi_bvalid = { 0x00c0, 6, 6, 0, 1 }, 189162306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci }, 189462306a36Sopenharmony_ci .chg_det = { 189562306a36Sopenharmony_ci .cp_det = { 0x00c0, 0, 0, 0, 1 }, 189662306a36Sopenharmony_ci .dcp_det = { 0x00c0, 0, 0, 0, 1 }, 189762306a36Sopenharmony_ci .dp_det = { 0x00c0, 1, 1, 1, 0 }, 189862306a36Sopenharmony_ci .idm_sink_en = { 0x0008, 5, 5, 1, 0 }, 189962306a36Sopenharmony_ci .idp_sink_en = { 0x0008, 5, 5, 0, 1 }, 190062306a36Sopenharmony_ci .idp_src_en = { 0x0008, 14, 14, 0, 1 }, 190162306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0008, 14, 14, 0, 1 }, 190262306a36Sopenharmony_ci .vdm_src_en = { 0x0008, 7, 6, 0, 3 }, 190362306a36Sopenharmony_ci .vdp_src_en = { 0x0008, 7, 6, 0, 3 }, 190462306a36Sopenharmony_ci }, 190562306a36Sopenharmony_ci }, 190662306a36Sopenharmony_ci { 190762306a36Sopenharmony_ci .reg = 0x8000, 190862306a36Sopenharmony_ci .num_ports = 1, 190962306a36Sopenharmony_ci .phy_tuning = rk3588_usb2phy_tuning, 191062306a36Sopenharmony_ci .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, 191162306a36Sopenharmony_ci .port_cfgs = { 191262306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 191362306a36Sopenharmony_ci .phy_sus = { 0x0008, 2, 2, 0, 1 }, 191462306a36Sopenharmony_ci .ls_det_en = { 0x0080, 0, 0, 0, 1 }, 191562306a36Sopenharmony_ci .ls_det_st = { 0x0084, 0, 0, 0, 1 }, 191662306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, 191762306a36Sopenharmony_ci .disfall_en = { 0x0080, 6, 6, 0, 1 }, 191862306a36Sopenharmony_ci .disfall_st = { 0x0084, 6, 6, 0, 1 }, 191962306a36Sopenharmony_ci .disfall_clr = { 0x0088, 6, 6, 0, 1 }, 192062306a36Sopenharmony_ci .disrise_en = { 0x0080, 5, 5, 0, 1 }, 192162306a36Sopenharmony_ci .disrise_st = { 0x0084, 5, 5, 0, 1 }, 192262306a36Sopenharmony_ci .disrise_clr = { 0x0088, 5, 5, 0, 1 }, 192362306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci }, 192662306a36Sopenharmony_ci }, 192762306a36Sopenharmony_ci { 192862306a36Sopenharmony_ci .reg = 0xc000, 192962306a36Sopenharmony_ci .num_ports = 1, 193062306a36Sopenharmony_ci .phy_tuning = rk3588_usb2phy_tuning, 193162306a36Sopenharmony_ci .clkout_ctl = { 0x0000, 0, 0, 1, 0 }, 193262306a36Sopenharmony_ci .port_cfgs = { 193362306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 193462306a36Sopenharmony_ci .phy_sus = { 0x0008, 2, 2, 0, 1 }, 193562306a36Sopenharmony_ci .ls_det_en = { 0x0080, 0, 0, 0, 1 }, 193662306a36Sopenharmony_ci .ls_det_st = { 0x0084, 0, 0, 0, 1 }, 193762306a36Sopenharmony_ci .ls_det_clr = { 0x0088, 0, 0, 0, 1 }, 193862306a36Sopenharmony_ci .disfall_en = { 0x0080, 6, 6, 0, 1 }, 193962306a36Sopenharmony_ci .disfall_st = { 0x0084, 6, 6, 0, 1 }, 194062306a36Sopenharmony_ci .disfall_clr = { 0x0088, 6, 6, 0, 1 }, 194162306a36Sopenharmony_ci .disrise_en = { 0x0080, 5, 5, 0, 1 }, 194262306a36Sopenharmony_ci .disrise_st = { 0x0084, 5, 5, 0, 1 }, 194362306a36Sopenharmony_ci .disrise_clr = { 0x0088, 5, 5, 0, 1 }, 194462306a36Sopenharmony_ci .utmi_ls = { 0x00c0, 10, 9, 0, 1 }, 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci }, 194762306a36Sopenharmony_ci }, 194862306a36Sopenharmony_ci { /* sentinel */ } 194962306a36Sopenharmony_ci}; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_cistatic const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { 195262306a36Sopenharmony_ci { 195362306a36Sopenharmony_ci .reg = 0x100, 195462306a36Sopenharmony_ci .num_ports = 2, 195562306a36Sopenharmony_ci .clkout_ctl = { 0x108, 4, 4, 1, 0 }, 195662306a36Sopenharmony_ci .port_cfgs = { 195762306a36Sopenharmony_ci [USB2PHY_PORT_OTG] = { 195862306a36Sopenharmony_ci .phy_sus = { 0x0100, 15, 0, 0, 0x1d1 }, 195962306a36Sopenharmony_ci .bvalid_det_en = { 0x0680, 3, 3, 0, 1 }, 196062306a36Sopenharmony_ci .bvalid_det_st = { 0x0690, 3, 3, 0, 1 }, 196162306a36Sopenharmony_ci .bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 }, 196262306a36Sopenharmony_ci .ls_det_en = { 0x0680, 2, 2, 0, 1 }, 196362306a36Sopenharmony_ci .ls_det_st = { 0x0690, 2, 2, 0, 1 }, 196462306a36Sopenharmony_ci .ls_det_clr = { 0x06a0, 2, 2, 0, 1 }, 196562306a36Sopenharmony_ci .utmi_bvalid = { 0x0804, 10, 10, 0, 1 }, 196662306a36Sopenharmony_ci .utmi_ls = { 0x0804, 13, 12, 0, 1 }, 196762306a36Sopenharmony_ci }, 196862306a36Sopenharmony_ci [USB2PHY_PORT_HOST] = { 196962306a36Sopenharmony_ci .phy_sus = { 0x0104, 15, 0, 0, 0x1d1 }, 197062306a36Sopenharmony_ci .ls_det_en = { 0x0680, 4, 4, 0, 1 }, 197162306a36Sopenharmony_ci .ls_det_st = { 0x0690, 4, 4, 0, 1 }, 197262306a36Sopenharmony_ci .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, 197362306a36Sopenharmony_ci .utmi_ls = { 0x0804, 9, 8, 0, 1 }, 197462306a36Sopenharmony_ci .utmi_hstdet = { 0x0804, 7, 7, 0, 1 } 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci }, 197762306a36Sopenharmony_ci .chg_det = { 197862306a36Sopenharmony_ci .opmode = { 0x0100, 3, 0, 5, 1 }, 197962306a36Sopenharmony_ci .cp_det = { 0x0804, 1, 1, 0, 1 }, 198062306a36Sopenharmony_ci .dcp_det = { 0x0804, 0, 0, 0, 1 }, 198162306a36Sopenharmony_ci .dp_det = { 0x0804, 2, 2, 0, 1 }, 198262306a36Sopenharmony_ci .idm_sink_en = { 0x0108, 8, 8, 0, 1 }, 198362306a36Sopenharmony_ci .idp_sink_en = { 0x0108, 7, 7, 0, 1 }, 198462306a36Sopenharmony_ci .idp_src_en = { 0x0108, 9, 9, 0, 1 }, 198562306a36Sopenharmony_ci .rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 }, 198662306a36Sopenharmony_ci .vdm_src_en = { 0x0108, 12, 12, 0, 1 }, 198762306a36Sopenharmony_ci .vdp_src_en = { 0x0108, 11, 11, 0, 1 }, 198862306a36Sopenharmony_ci }, 198962306a36Sopenharmony_ci }, 199062306a36Sopenharmony_ci { /* sentinel */ } 199162306a36Sopenharmony_ci}; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_cistatic const struct of_device_id rockchip_usb2phy_dt_match[] = { 199462306a36Sopenharmony_ci { .compatible = "rockchip,px30-usb2phy", .data = &rk3328_phy_cfgs }, 199562306a36Sopenharmony_ci { .compatible = "rockchip,rk3228-usb2phy", .data = &rk3228_phy_cfgs }, 199662306a36Sopenharmony_ci { .compatible = "rockchip,rk3308-usb2phy", .data = &rk3308_phy_cfgs }, 199762306a36Sopenharmony_ci { .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs }, 199862306a36Sopenharmony_ci { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, 199962306a36Sopenharmony_ci { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, 200062306a36Sopenharmony_ci { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, 200162306a36Sopenharmony_ci { .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs }, 200262306a36Sopenharmony_ci { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, 200362306a36Sopenharmony_ci {} 200462306a36Sopenharmony_ci}; 200562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_cistatic struct platform_driver rockchip_usb2phy_driver = { 200862306a36Sopenharmony_ci .probe = rockchip_usb2phy_probe, 200962306a36Sopenharmony_ci .driver = { 201062306a36Sopenharmony_ci .name = "rockchip-usb2phy", 201162306a36Sopenharmony_ci .of_match_table = rockchip_usb2phy_dt_match, 201262306a36Sopenharmony_ci }, 201362306a36Sopenharmony_ci}; 201462306a36Sopenharmony_cimodule_platform_driver(rockchip_usb2phy_driver); 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ciMODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>"); 201762306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip USB2.0 PHY driver"); 201862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2019