1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
7 #include <linux/interrupt.h>
8 #include <linux/kernel.h>
9 #include <linux/mod_devicetable.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
13 #include <linux/regulator/consumer.h>
14 #include <linux/slab.h>
15 #include <linux/usb/role.h>
16 #include <linux/usb/typec_mux.h>
18 #define TYPEC_MISC_STATUS 0xb
19 #define CC_ATTACHED BIT(0)
20 #define CC_ORIENTATION BIT(1)
21 #define SNK_SRC_MODE BIT(6)
22 #define TYPEC_MODE_CFG 0x44
23 #define TYPEC_DISABLE_CMD BIT(0)
24 #define EN_SNK_ONLY BIT(1)
25 #define EN_SRC_ONLY BIT(2)
26 #define TYPEC_VCONN_CONTROL 0x46
27 #define VCONN_EN_SRC BIT(0)
28 #define VCONN_EN_VAL BIT(1)
29 #define TYPEC_EXIT_STATE_CFG 0x50
30 #define SEL_SRC_UPPER_REF BIT(2)
31 #define TYPEC_INTR_EN_CFG_1 0x5e
32 #define TYPEC_INTR_EN_CFG_1_MASK GENMASK(7, 0)
34 struct qcom_pmic_typec
{
36 struct regmap
*regmap
;
39 struct typec_port
*port
;
40 struct usb_role_switch
*role_sw
;
42 struct regulator
*vbus_reg
;
46 static void qcom_pmic_typec_enable_vbus_regulator(struct qcom_pmic_typec
47 *qcom_usb
, bool enable
)
51 if (enable
== qcom_usb
->vbus_enabled
)
55 ret
= regulator_enable(qcom_usb
->vbus_reg
);
59 ret
= regulator_disable(qcom_usb
->vbus_reg
);
63 qcom_usb
->vbus_enabled
= enable
;
66 static void qcom_pmic_typec_check_connection(struct qcom_pmic_typec
*qcom_usb
)
68 enum typec_orientation orientation
;
73 regmap_read(qcom_usb
->regmap
, qcom_usb
->base
+ TYPEC_MISC_STATUS
,
76 if (stat
& CC_ATTACHED
) {
77 orientation
= (stat
& CC_ORIENTATION
) ?
78 TYPEC_ORIENTATION_REVERSE
:
79 TYPEC_ORIENTATION_NORMAL
;
80 typec_set_orientation(qcom_usb
->port
, orientation
);
82 role
= (stat
& SNK_SRC_MODE
) ? USB_ROLE_HOST
: USB_ROLE_DEVICE
;
83 if (role
== USB_ROLE_HOST
)
92 qcom_pmic_typec_enable_vbus_regulator(qcom_usb
, enable_vbus
);
93 usb_role_switch_set_role(qcom_usb
->role_sw
, role
);
96 static irqreturn_t
qcom_pmic_typec_interrupt(int irq
, void *_qcom_usb
)
98 struct qcom_pmic_typec
*qcom_usb
= _qcom_usb
;
100 qcom_pmic_typec_check_connection(qcom_usb
);
104 static void qcom_pmic_typec_typec_hw_init(struct qcom_pmic_typec
*qcom_usb
,
105 enum typec_port_type type
)
109 regmap_update_bits(qcom_usb
->regmap
,
110 qcom_usb
->base
+ TYPEC_INTR_EN_CFG_1
,
111 TYPEC_INTR_EN_CFG_1_MASK
, 0);
113 if (type
== TYPEC_PORT_SRC
)
115 else if (type
== TYPEC_PORT_SNK
)
118 regmap_update_bits(qcom_usb
->regmap
, qcom_usb
->base
+ TYPEC_MODE_CFG
,
119 EN_SNK_ONLY
| EN_SRC_ONLY
, mode
);
121 regmap_update_bits(qcom_usb
->regmap
,
122 qcom_usb
->base
+ TYPEC_VCONN_CONTROL
,
123 VCONN_EN_SRC
| VCONN_EN_VAL
, VCONN_EN_SRC
);
124 regmap_update_bits(qcom_usb
->regmap
,
125 qcom_usb
->base
+ TYPEC_EXIT_STATE_CFG
,
126 SEL_SRC_UPPER_REF
, SEL_SRC_UPPER_REF
);
129 static int qcom_pmic_typec_probe(struct platform_device
*pdev
)
131 struct qcom_pmic_typec
*qcom_usb
;
132 struct device
*dev
= &pdev
->dev
;
133 struct fwnode_handle
*fwnode
;
134 struct typec_capability cap
;
139 ret
= device_property_read_u32(dev
, "reg", ®
);
141 dev_err(dev
, "missing base address\n");
145 qcom_usb
= devm_kzalloc(dev
, sizeof(*qcom_usb
), GFP_KERNEL
);
150 qcom_usb
->base
= reg
;
152 qcom_usb
->regmap
= dev_get_regmap(dev
->parent
, NULL
);
153 if (!qcom_usb
->regmap
) {
154 dev_err(dev
, "Failed to get regmap\n");
158 qcom_usb
->vbus_reg
= devm_regulator_get(qcom_usb
->dev
, "usb_vbus");
159 if (IS_ERR(qcom_usb
->vbus_reg
))
160 return PTR_ERR(qcom_usb
->vbus_reg
);
162 fwnode
= device_get_named_child_node(dev
, "connector");
166 ret
= fwnode_property_read_string(fwnode
, "power-role", &buf
);
168 role
= typec_find_port_power_role(buf
);
170 role
= TYPEC_PORT_SNK
;
172 role
= TYPEC_PORT_SNK
;
176 ret
= fwnode_property_read_string(fwnode
, "data-role", &buf
);
178 role
= typec_find_port_data_role(buf
);
180 role
= TYPEC_PORT_UFP
;
182 role
= TYPEC_PORT_UFP
;
186 cap
.prefer_role
= TYPEC_NO_PREFERRED_ROLE
;
188 qcom_usb
->port
= typec_register_port(dev
, &cap
);
189 if (IS_ERR(qcom_usb
->port
)) {
190 ret
= PTR_ERR(qcom_usb
->port
);
191 dev_err(dev
, "Failed to register type c port %d\n", ret
);
194 fwnode_handle_put(fwnode
);
196 qcom_usb
->role_sw
= fwnode_usb_role_switch_get(dev_fwnode(qcom_usb
->dev
));
197 if (IS_ERR(qcom_usb
->role_sw
)) {
198 if (PTR_ERR(qcom_usb
->role_sw
) != -EPROBE_DEFER
)
199 dev_err(dev
, "failed to get role switch\n");
200 ret
= PTR_ERR(qcom_usb
->role_sw
);
204 irq
= platform_get_irq(pdev
, 0);
206 goto err_usb_role_sw
;
208 ret
= devm_request_threaded_irq(qcom_usb
->dev
, irq
, NULL
,
209 qcom_pmic_typec_interrupt
, IRQF_ONESHOT
,
210 "qcom-pmic-typec", qcom_usb
);
212 dev_err(&pdev
->dev
, "Could not request IRQ\n");
213 goto err_usb_role_sw
;
216 platform_set_drvdata(pdev
, qcom_usb
);
217 qcom_pmic_typec_typec_hw_init(qcom_usb
, cap
.type
);
218 qcom_pmic_typec_check_connection(qcom_usb
);
223 usb_role_switch_put(qcom_usb
->role_sw
);
225 typec_unregister_port(qcom_usb
->port
);
227 fwnode_handle_put(fwnode
);
232 static int qcom_pmic_typec_remove(struct platform_device
*pdev
)
234 struct qcom_pmic_typec
*qcom_usb
= platform_get_drvdata(pdev
);
236 usb_role_switch_set_role(qcom_usb
->role_sw
, USB_ROLE_NONE
);
237 qcom_pmic_typec_enable_vbus_regulator(qcom_usb
, 0);
239 typec_unregister_port(qcom_usb
->port
);
240 usb_role_switch_put(qcom_usb
->role_sw
);
245 static const struct of_device_id qcom_pmic_typec_table
[] = {
246 { .compatible
= "qcom,pm8150b-usb-typec" },
249 MODULE_DEVICE_TABLE(of
, qcom_pmic_typec_table
);
251 static struct platform_driver qcom_pmic_typec
= {
253 .name
= "qcom,pmic-typec",
254 .of_match_table
= qcom_pmic_typec_table
,
256 .probe
= qcom_pmic_typec_probe
,
257 .remove
= qcom_pmic_typec_remove
,
259 module_platform_driver(qcom_pmic_typec
);
261 MODULE_DESCRIPTION("QCOM PMIC USB type C driver");
262 MODULE_LICENSE("GPL v2");