Skip to content

Commit d2f9b93

Browse files
lumaggregkh
authored andcommitted
usb: typec: qcom-pmic-typec: allow different implementations for the PD PHY
Rework Qualcomm PMIC TCPM driver to allow different platform-specific implementations of the PD PHY interface. While majority of platforms has the same of register for the PD PHY, some obscure ones (PMI632) do not have real PD PHY support. Add proper interface between the main module and the PD PHY backend to allow switching the PD PHY implementation. Tested-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Acked-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20240113-pmi632-typec-v2-7-182d9aa0a5b3@linaro.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 65145a0 commit d2f9b93

File tree

5 files changed

+171
-195
lines changed

5 files changed

+171
-195
lines changed

drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c

Lines changed: 5 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,15 @@
2020

2121
#include <drm/bridge/aux-bridge.h>
2222

23+
#include "qcom_pmic_typec.h"
2324
#include "qcom_pmic_typec_pdphy.h"
2425
#include "qcom_pmic_typec_port.h"
2526

2627
struct pmic_typec_resources {
27-
struct pmic_typec_pdphy_resources *pdphy_res;
28+
const struct pmic_typec_pdphy_resources *pdphy_res;
2829
struct pmic_typec_port_resources *port_res;
2930
};
3031

31-
struct pmic_typec {
32-
struct device *dev;
33-
struct tcpm_port *tcpm_port;
34-
struct tcpc_dev tcpc;
35-
struct pmic_typec_pdphy *pmic_typec_pdphy;
36-
struct pmic_typec_port *pmic_typec_port;
37-
bool vbus_enabled;
38-
struct mutex lock; /* VBUS state serialization */
39-
};
40-
41-
#define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc)
42-
4332
static int qcom_pmic_typec_get_vbus(struct tcpc_dev *tcpc)
4433
{
4534
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
@@ -116,34 +105,6 @@ static int qcom_pmic_typec_start_toggling(struct tcpc_dev *tcpc,
116105
port_type, cc);
117106
}
118107

119-
static int qcom_pmic_typec_set_roles(struct tcpc_dev *tcpc, bool attached,
120-
enum typec_role power_role,
121-
enum typec_data_role data_role)
122-
{
123-
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
124-
125-
return qcom_pmic_typec_pdphy_set_roles(tcpm->pmic_typec_pdphy,
126-
power_role, data_role);
127-
}
128-
129-
static int qcom_pmic_typec_set_pd_rx(struct tcpc_dev *tcpc, bool on)
130-
{
131-
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
132-
133-
return qcom_pmic_typec_pdphy_set_pd_rx(tcpm->pmic_typec_pdphy, on);
134-
}
135-
136-
static int qcom_pmic_typec_pd_transmit(struct tcpc_dev *tcpc,
137-
enum tcpm_transmit_type type,
138-
const struct pd_message *msg,
139-
unsigned int negotiated_rev)
140-
{
141-
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
142-
143-
return qcom_pmic_typec_pdphy_pd_transmit(tcpm->pmic_typec_pdphy, type,
144-
msg, negotiated_rev);
145-
}
146-
147108
static int qcom_pmic_typec_init(struct tcpc_dev *tcpc)
148109
{
149110
return 0;
@@ -177,9 +138,6 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
177138
tcpm->tcpc.set_polarity = qcom_pmic_typec_set_polarity;
178139
tcpm->tcpc.set_vconn = qcom_pmic_typec_set_vconn;
179140
tcpm->tcpc.start_toggling = qcom_pmic_typec_start_toggling;
180-
tcpm->tcpc.set_pd_rx = qcom_pmic_typec_set_pd_rx;
181-
tcpm->tcpc.set_roles = qcom_pmic_typec_set_roles;
182-
tcpm->tcpc.pd_transmit = qcom_pmic_typec_pd_transmit;
183141

184142
regmap = dev_get_regmap(dev->parent, NULL);
185143
if (!regmap) {
@@ -195,16 +153,12 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
195153
if (IS_ERR(tcpm->pmic_typec_port))
196154
return PTR_ERR(tcpm->pmic_typec_port);
197155

198-
tcpm->pmic_typec_pdphy = qcom_pmic_typec_pdphy_alloc(dev);
199-
if (IS_ERR(tcpm->pmic_typec_pdphy))
200-
return PTR_ERR(tcpm->pmic_typec_pdphy);
201-
202156
ret = qcom_pmic_typec_port_probe(pdev, tcpm->pmic_typec_port,
203157
res->port_res, regmap, base[0]);
204158
if (ret)
205159
return ret;
206160

207-
ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm->pmic_typec_pdphy,
161+
ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm,
208162
res->pdphy_res, regmap, base[1]);
209163
if (ret)
210164
return ret;
@@ -231,8 +185,7 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev)
231185
if (ret)
232186
goto fwnode_remove;
233187

234-
ret = qcom_pmic_typec_pdphy_start(tcpm->pmic_typec_pdphy,
235-
tcpm->tcpm_port);
188+
ret = tcpm->pdphy_start(tcpm, tcpm->tcpm_port);
236189
if (ret)
237190
goto fwnode_remove;
238191

@@ -248,46 +201,12 @@ static void qcom_pmic_typec_remove(struct platform_device *pdev)
248201
{
249202
struct pmic_typec *tcpm = platform_get_drvdata(pdev);
250203

251-
qcom_pmic_typec_pdphy_stop(tcpm->pmic_typec_pdphy);
204+
tcpm->pdphy_stop(tcpm);
252205
qcom_pmic_typec_port_stop(tcpm->pmic_typec_port);
253206
tcpm_unregister_port(tcpm->tcpm_port);
254207
fwnode_remove_software_node(tcpm->tcpc.fwnode);
255208
}
256209

257-
static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = {
258-
.irq_params = {
259-
{
260-
.virq = PMIC_PDPHY_SIG_TX_IRQ,
261-
.irq_name = "sig-tx",
262-
},
263-
{
264-
.virq = PMIC_PDPHY_SIG_RX_IRQ,
265-
.irq_name = "sig-rx",
266-
},
267-
{
268-
.virq = PMIC_PDPHY_MSG_TX_IRQ,
269-
.irq_name = "msg-tx",
270-
},
271-
{
272-
.virq = PMIC_PDPHY_MSG_RX_IRQ,
273-
.irq_name = "msg-rx",
274-
},
275-
{
276-
.virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ,
277-
.irq_name = "msg-tx-failed",
278-
},
279-
{
280-
.virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ,
281-
.irq_name = "msg-tx-discarded",
282-
},
283-
{
284-
.virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ,
285-
.irq_name = "msg-rx-discarded",
286-
},
287-
},
288-
.nr_irqs = 7,
289-
};
290-
291210
static struct pmic_typec_port_resources pm8150b_port_res = {
292211
.irq_params = {
293212
{
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (c) 2023, Linaro Ltd. All rights reserved.
4+
*/
5+
6+
#ifndef __QCOM_PMIC_TYPEC_H__
7+
#define __QCOM_PMIC_TYPEC_H__
8+
9+
struct pmic_typec {
10+
struct device *dev;
11+
struct tcpm_port *tcpm_port;
12+
struct tcpc_dev tcpc;
13+
struct pmic_typec_pdphy *pmic_typec_pdphy;
14+
struct pmic_typec_port *pmic_typec_port;
15+
bool vbus_enabled;
16+
struct mutex lock; /* VBUS state serialization */
17+
18+
int (*pdphy_start)(struct pmic_typec *tcpm,
19+
struct tcpm_port *tcpm_port);
20+
void (*pdphy_stop)(struct pmic_typec *tcpm);
21+
};
22+
23+
#define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc)
24+
25+
#endif

drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c

Lines changed: 135 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,74 @@
1414
#include <linux/slab.h>
1515
#include <linux/usb/pd.h>
1616
#include <linux/usb/tcpm.h>
17+
#include "qcom_pmic_typec.h"
1718
#include "qcom_pmic_typec_pdphy.h"
1819

20+
/* PD PHY register offsets and bit fields */
21+
#define USB_PDPHY_MSG_CONFIG_REG 0x40
22+
#define MSG_CONFIG_PORT_DATA_ROLE BIT(3)
23+
#define MSG_CONFIG_PORT_POWER_ROLE BIT(2)
24+
#define MSG_CONFIG_SPEC_REV_MASK (BIT(1) | BIT(0))
25+
26+
#define USB_PDPHY_EN_CONTROL_REG 0x46
27+
#define CONTROL_ENABLE BIT(0)
28+
29+
#define USB_PDPHY_RX_STATUS_REG 0x4A
30+
#define RX_FRAME_TYPE (BIT(0) | BIT(1) | BIT(2))
31+
32+
#define USB_PDPHY_FRAME_FILTER_REG 0x4C
33+
#define FRAME_FILTER_EN_HARD_RESET BIT(5)
34+
#define FRAME_FILTER_EN_SOP BIT(0)
35+
36+
#define USB_PDPHY_TX_SIZE_REG 0x42
37+
#define TX_SIZE_MASK 0xF
38+
39+
#define USB_PDPHY_TX_CONTROL_REG 0x44
40+
#define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5)
41+
#define TX_CONTROL_FRAME_TYPE(n) (((n) & 0x7) << 2)
42+
#define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2)
43+
#define TX_CONTROL_SEND_SIGNAL BIT(1)
44+
#define TX_CONTROL_SEND_MSG BIT(0)
45+
46+
#define USB_PDPHY_RX_SIZE_REG 0x48
47+
48+
#define USB_PDPHY_RX_ACKNOWLEDGE_REG 0x4B
49+
#define RX_BUFFER_TOKEN BIT(0)
50+
51+
#define USB_PDPHY_BIST_MODE_REG 0x4E
52+
#define BIST_MODE_MASK 0xF
53+
#define BIST_ENABLE BIT(7)
54+
#define PD_MSG_BIST 0x3
55+
#define PD_BIST_TEST_DATA_MODE 0x8
56+
57+
#define USB_PDPHY_TX_BUFFER_HDR_REG 0x60
58+
#define USB_PDPHY_TX_BUFFER_DATA_REG 0x62
59+
60+
#define USB_PDPHY_RX_BUFFER_REG 0x80
61+
62+
/* VDD regulator */
63+
#define VDD_PDPHY_VOL_MIN 2800000 /* uV */
64+
#define VDD_PDPHY_VOL_MAX 3300000 /* uV */
65+
#define VDD_PDPHY_HPM_LOAD 3000 /* uA */
66+
67+
/* Message Spec Rev field */
68+
#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3)
69+
70+
/* timers */
71+
#define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */
72+
#define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */
73+
74+
/* Interrupt numbers */
75+
#define PMIC_PDPHY_SIG_TX_IRQ 0x0
76+
#define PMIC_PDPHY_SIG_RX_IRQ 0x1
77+
#define PMIC_PDPHY_MSG_TX_IRQ 0x2
78+
#define PMIC_PDPHY_MSG_RX_IRQ 0x3
79+
#define PMIC_PDPHY_MSG_TX_FAIL_IRQ 0x4
80+
#define PMIC_PDPHY_MSG_TX_DISCARD_IRQ 0x5
81+
#define PMIC_PDPHY_MSG_RX_DISCARD_IRQ 0x6
82+
#define PMIC_PDPHY_FR_SWAP_IRQ 0x7
83+
84+
1985
struct pmic_typec_pdphy_irq_data {
2086
int virq;
2187
int irq;
@@ -231,11 +297,13 @@ qcom_pmic_typec_pdphy_pd_transmit_payload(struct pmic_typec_pdphy *pmic_typec_pd
231297
return ret;
232298
}
233299

234-
int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy,
235-
enum tcpm_transmit_type type,
236-
const struct pd_message *msg,
237-
unsigned int negotiated_rev)
300+
static int qcom_pmic_typec_pdphy_pd_transmit(struct tcpc_dev *tcpc,
301+
enum tcpm_transmit_type type,
302+
const struct pd_message *msg,
303+
unsigned int negotiated_rev)
238304
{
305+
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
306+
struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
239307
struct device *dev = pmic_typec_pdphy->dev;
240308
int ret;
241309

@@ -336,8 +404,10 @@ static irqreturn_t qcom_pmic_typec_pdphy_isr(int irq, void *dev_id)
336404
return IRQ_HANDLED;
337405
}
338406

339-
int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on)
407+
static int qcom_pmic_typec_pdphy_set_pd_rx(struct tcpc_dev *tcpc, bool on)
340408
{
409+
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
410+
struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
341411
unsigned long flags;
342412
int ret;
343413

@@ -353,10 +423,12 @@ int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, b
353423
return ret;
354424
}
355425

356-
int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy,
357-
enum typec_role power_role,
358-
enum typec_data_role data_role)
426+
static int qcom_pmic_typec_pdphy_set_roles(struct tcpc_dev *tcpc, bool attached,
427+
enum typec_role power_role,
428+
enum typec_data_role data_role)
359429
{
430+
struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
431+
struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
360432
struct device *dev = pmic_typec_pdphy->dev;
361433
unsigned long flags;
362434
int ret;
@@ -437,9 +509,10 @@ static int pmic_typec_pdphy_reset(struct pmic_typec_pdphy *pmic_typec_pdphy)
437509
return ret;
438510
}
439511

440-
int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
441-
struct tcpm_port *tcpm_port)
512+
static int qcom_pmic_typec_pdphy_start(struct pmic_typec *tcpm,
513+
struct tcpm_port *tcpm_port)
442514
{
515+
struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
443516
int i;
444517
int ret;
445518

@@ -459,8 +532,9 @@ int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
459532
return 0;
460533
}
461534

462-
void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy)
535+
static void qcom_pmic_typec_pdphy_stop(struct pmic_typec *tcpm)
463536
{
537+
struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy;
464538
int i;
465539

466540
for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++)
@@ -471,21 +545,21 @@ void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy)
471545
regulator_disable(pmic_typec_pdphy->vdd_pdphy);
472546
}
473547

474-
struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev)
475-
{
476-
return devm_kzalloc(dev, sizeof(struct pmic_typec_pdphy), GFP_KERNEL);
477-
}
478-
479548
int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev,
480-
struct pmic_typec_pdphy *pmic_typec_pdphy,
481-
struct pmic_typec_pdphy_resources *res,
549+
struct pmic_typec *tcpm,
550+
const struct pmic_typec_pdphy_resources *res,
482551
struct regmap *regmap,
483552
u32 base)
484553
{
554+
struct pmic_typec_pdphy *pmic_typec_pdphy;
485555
struct device *dev = &pdev->dev;
486556
struct pmic_typec_pdphy_irq_data *irq_data;
487557
int i, ret, irq;
488558

559+
pmic_typec_pdphy = devm_kzalloc(dev, sizeof(*pmic_typec_pdphy), GFP_KERNEL);
560+
if (!pmic_typec_pdphy)
561+
return -ENOMEM;
562+
489563
if (!res->nr_irqs || res->nr_irqs > PMIC_PDPHY_MAX_IRQS)
490564
return -EINVAL;
491565

@@ -524,5 +598,48 @@ int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev,
524598
return ret;
525599
}
526600

601+
tcpm->pmic_typec_pdphy = pmic_typec_pdphy;
602+
603+
tcpm->tcpc.set_pd_rx = qcom_pmic_typec_pdphy_set_pd_rx;
604+
tcpm->tcpc.set_roles = qcom_pmic_typec_pdphy_set_roles;
605+
tcpm->tcpc.pd_transmit = qcom_pmic_typec_pdphy_pd_transmit;
606+
607+
tcpm->pdphy_start = qcom_pmic_typec_pdphy_start;
608+
tcpm->pdphy_stop = qcom_pmic_typec_pdphy_stop;
609+
527610
return 0;
528611
}
612+
613+
const struct pmic_typec_pdphy_resources pm8150b_pdphy_res = {
614+
.irq_params = {
615+
{
616+
.virq = PMIC_PDPHY_SIG_TX_IRQ,
617+
.irq_name = "sig-tx",
618+
},
619+
{
620+
.virq = PMIC_PDPHY_SIG_RX_IRQ,
621+
.irq_name = "sig-rx",
622+
},
623+
{
624+
.virq = PMIC_PDPHY_MSG_TX_IRQ,
625+
.irq_name = "msg-tx",
626+
},
627+
{
628+
.virq = PMIC_PDPHY_MSG_RX_IRQ,
629+
.irq_name = "msg-rx",
630+
},
631+
{
632+
.virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ,
633+
.irq_name = "msg-tx-failed",
634+
},
635+
{
636+
.virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ,
637+
.irq_name = "msg-tx-discarded",
638+
},
639+
{
640+
.virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ,
641+
.irq_name = "msg-rx-discarded",
642+
},
643+
},
644+
.nr_irqs = 7,
645+
};

0 commit comments

Comments
 (0)