1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2016 Linaro Ltd
5 #include <linux/module.h>
6 #include <linux/ulpi/driver.h>
7 #include <linux/ulpi/regs.h>
9 #include <linux/regulator/consumer.h>
11 #include <linux/phy/phy.h>
12 #include <linux/reset.h>
13 #include <linux/extcon.h>
14 #include <linux/notifier.h>
16 #define ULPI_PWR_CLK_MNG_REG 0x88
17 # define ULPI_PWR_OTG_COMP_DISABLE BIT(0)
19 #define ULPI_MISC_A 0x96
20 # define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1)
21 # define ULPI_MISC_A_VBUSVLDEXT BIT(0)
29 struct qcom_usb_hs_phy
{
33 struct clk
*sleep_clk
;
34 struct regulator
*v1p8
;
35 struct regulator
*v3p3
;
36 struct reset_control
*reset
;
37 struct ulpi_seq
*init_seq
;
38 struct extcon_dev
*vbus_edev
;
39 struct notifier_block vbus_notify
;
42 static int qcom_usb_hs_phy_set_mode(struct phy
*phy
,
43 enum phy_mode mode
, int submode
)
45 struct qcom_usb_hs_phy
*uphy
= phy_get_drvdata(phy
);
49 if (!uphy
->vbus_edev
) {
53 case PHY_MODE_USB_OTG
:
54 case PHY_MODE_USB_HOST
:
55 val
|= ULPI_INT_IDGRD
;
57 case PHY_MODE_USB_DEVICE
:
58 val
|= ULPI_INT_SESS_VALID
;
64 ret
= ulpi_write(uphy
->ulpi
, ULPI_USB_INT_EN_RISE
, val
);
67 ret
= ulpi_write(uphy
->ulpi
, ULPI_USB_INT_EN_FALL
, val
);
70 case PHY_MODE_USB_OTG
:
71 case PHY_MODE_USB_DEVICE
:
72 addr
= ULPI_SET(ULPI_MISC_A
);
74 case PHY_MODE_USB_HOST
:
75 addr
= ULPI_CLR(ULPI_MISC_A
);
81 ret
= ulpi_write(uphy
->ulpi
, ULPI_SET(ULPI_PWR_CLK_MNG_REG
),
82 ULPI_PWR_OTG_COMP_DISABLE
);
85 ret
= ulpi_write(uphy
->ulpi
, addr
, ULPI_MISC_A_VBUSVLDEXTSEL
);
92 qcom_usb_hs_phy_vbus_notifier(struct notifier_block
*nb
, unsigned long event
,
95 struct qcom_usb_hs_phy
*uphy
;
98 uphy
= container_of(nb
, struct qcom_usb_hs_phy
, vbus_notify
);
101 addr
= ULPI_SET(ULPI_MISC_A
);
103 addr
= ULPI_CLR(ULPI_MISC_A
);
105 return ulpi_write(uphy
->ulpi
, addr
, ULPI_MISC_A_VBUSVLDEXT
);
108 static int qcom_usb_hs_phy_power_on(struct phy
*phy
)
110 struct qcom_usb_hs_phy
*uphy
= phy_get_drvdata(phy
);
111 struct ulpi
*ulpi
= uphy
->ulpi
;
112 const struct ulpi_seq
*seq
;
115 ret
= clk_prepare_enable(uphy
->ref_clk
);
119 ret
= clk_prepare_enable(uphy
->sleep_clk
);
123 ret
= regulator_set_load(uphy
->v1p8
, 50000);
127 ret
= regulator_enable(uphy
->v1p8
);
131 ret
= regulator_set_voltage_triplet(uphy
->v3p3
, 3050000, 3300000,
136 ret
= regulator_set_load(uphy
->v3p3
, 50000);
140 ret
= regulator_enable(uphy
->v3p3
);
144 for (seq
= uphy
->init_seq
; seq
->addr
; seq
++) {
145 ret
= ulpi_write(ulpi
, ULPI_EXT_VENDOR_SPECIFIC
+ seq
->addr
,
152 ret
= reset_control_reset(uphy
->reset
);
157 if (uphy
->vbus_edev
) {
158 state
= extcon_get_state(uphy
->vbus_edev
, EXTCON_USB
);
159 /* setup initial state */
160 qcom_usb_hs_phy_vbus_notifier(&uphy
->vbus_notify
, state
,
162 ret
= extcon_register_notifier(uphy
->vbus_edev
, EXTCON_USB
,
170 regulator_disable(uphy
->v3p3
);
172 regulator_disable(uphy
->v1p8
);
174 clk_disable_unprepare(uphy
->sleep_clk
);
176 clk_disable_unprepare(uphy
->ref_clk
);
180 static int qcom_usb_hs_phy_power_off(struct phy
*phy
)
182 struct qcom_usb_hs_phy
*uphy
= phy_get_drvdata(phy
);
185 extcon_unregister_notifier(uphy
->vbus_edev
, EXTCON_USB
,
187 regulator_disable(uphy
->v3p3
);
188 regulator_disable(uphy
->v1p8
);
189 clk_disable_unprepare(uphy
->sleep_clk
);
190 clk_disable_unprepare(uphy
->ref_clk
);
195 static const struct phy_ops qcom_usb_hs_phy_ops
= {
196 .power_on
= qcom_usb_hs_phy_power_on
,
197 .power_off
= qcom_usb_hs_phy_power_off
,
198 .set_mode
= qcom_usb_hs_phy_set_mode
,
199 .owner
= THIS_MODULE
,
202 static int qcom_usb_hs_phy_probe(struct ulpi
*ulpi
)
204 struct qcom_usb_hs_phy
*uphy
;
205 struct phy_provider
*p
;
207 struct regulator
*reg
;
208 struct reset_control
*reset
;
212 uphy
= devm_kzalloc(&ulpi
->dev
, sizeof(*uphy
), GFP_KERNEL
);
215 ulpi_set_drvdata(ulpi
, uphy
);
218 size
= of_property_count_u8_elems(ulpi
->dev
.of_node
, "qcom,init-seq");
221 uphy
->init_seq
= devm_kmalloc_array(&ulpi
->dev
, (size
/ 2) + 1,
222 sizeof(*uphy
->init_seq
), GFP_KERNEL
);
225 ret
= of_property_read_u8_array(ulpi
->dev
.of_node
, "qcom,init-seq",
226 (u8
*)uphy
->init_seq
, size
);
230 uphy
->init_seq
[size
/ 2].addr
= uphy
->init_seq
[size
/ 2].val
= 0;
232 uphy
->ref_clk
= clk
= devm_clk_get(&ulpi
->dev
, "ref");
236 uphy
->sleep_clk
= clk
= devm_clk_get(&ulpi
->dev
, "sleep");
240 uphy
->v1p8
= reg
= devm_regulator_get(&ulpi
->dev
, "v1p8");
244 uphy
->v3p3
= reg
= devm_regulator_get(&ulpi
->dev
, "v3p3");
248 uphy
->reset
= reset
= devm_reset_control_get(&ulpi
->dev
, "por");
250 if (PTR_ERR(reset
) == -EPROBE_DEFER
)
251 return PTR_ERR(reset
);
255 uphy
->phy
= devm_phy_create(&ulpi
->dev
, ulpi
->dev
.of_node
,
256 &qcom_usb_hs_phy_ops
);
257 if (IS_ERR(uphy
->phy
))
258 return PTR_ERR(uphy
->phy
);
260 uphy
->vbus_edev
= extcon_get_edev_by_phandle(&ulpi
->dev
, 0);
261 if (IS_ERR(uphy
->vbus_edev
)) {
262 if (PTR_ERR(uphy
->vbus_edev
) != -ENODEV
)
263 return PTR_ERR(uphy
->vbus_edev
);
264 uphy
->vbus_edev
= NULL
;
267 uphy
->vbus_notify
.notifier_call
= qcom_usb_hs_phy_vbus_notifier
;
268 phy_set_drvdata(uphy
->phy
, uphy
);
270 p
= devm_of_phy_provider_register(&ulpi
->dev
, of_phy_simple_xlate
);
271 return PTR_ERR_OR_ZERO(p
);
274 static const struct of_device_id qcom_usb_hs_phy_match
[] = {
275 { .compatible
= "qcom,usb-hs-phy", },
278 MODULE_DEVICE_TABLE(of
, qcom_usb_hs_phy_match
);
280 static struct ulpi_driver qcom_usb_hs_phy_driver
= {
281 .probe
= qcom_usb_hs_phy_probe
,
283 .name
= "qcom_usb_hs_phy",
284 .of_match_table
= qcom_usb_hs_phy_match
,
287 module_ulpi_driver(qcom_usb_hs_phy_driver
);
289 MODULE_DESCRIPTION("Qualcomm USB HS phy");
290 MODULE_LICENSE("GPL v2");