11
11
#include <linux/of.h>
12
12
#include <linux/platform_data/cros_ec_commands.h>
13
13
#include <linux/platform_data/cros_ec_proto.h>
14
+ #include <linux/platform_data/cros_usbpd_notify.h>
14
15
#include <linux/platform_device.h>
15
16
#include <linux/usb/typec.h>
16
17
17
18
#define DRV_NAME "cros-ec-typec"
18
19
20
+ /* Per port data. */
21
+ struct cros_typec_port {
22
+ struct typec_port * port ;
23
+ /* Initial capabilities for the port. */
24
+ struct typec_capability caps ;
25
+ struct typec_partner * partner ;
26
+ /* Port partner PD identity info. */
27
+ struct usb_pd_identity p_identity ;
28
+ };
29
+
19
30
/* Platform-specific data for the Chrome OS EC Type C controller. */
20
31
struct cros_typec_data {
21
32
struct device * dev ;
22
33
struct cros_ec_device * ec ;
23
34
int num_ports ;
24
35
unsigned int cmd_ver ;
25
36
/* Array of ports, indexed by port number. */
26
- struct typec_port * ports [EC_USB_PD_MAX_PORTS ];
27
- /* Initial capabilities for each port. */
28
- struct typec_capability * caps [EC_USB_PD_MAX_PORTS ];
37
+ struct cros_typec_port * ports [EC_USB_PD_MAX_PORTS ];
38
+ struct notifier_block nb ;
29
39
};
30
40
31
41
static int cros_typec_parse_port_props (struct typec_capability * cap ,
@@ -74,14 +84,25 @@ static int cros_typec_parse_port_props(struct typec_capability *cap,
74
84
return 0 ;
75
85
}
76
86
87
+ static void cros_unregister_ports (struct cros_typec_data * typec )
88
+ {
89
+ int i ;
90
+
91
+ for (i = 0 ; i < typec -> num_ports ; i ++ ) {
92
+ if (!typec -> ports [i ])
93
+ continue ;
94
+ typec_unregister_port (typec -> ports [i ]-> port );
95
+ }
96
+ }
97
+
77
98
static int cros_typec_init_ports (struct cros_typec_data * typec )
78
99
{
79
100
struct device * dev = typec -> dev ;
80
101
struct typec_capability * cap ;
81
102
struct fwnode_handle * fwnode ;
103
+ struct cros_typec_port * cros_port ;
82
104
const char * port_prop ;
83
105
int ret ;
84
- int i ;
85
106
int nports ;
86
107
u32 port_num = 0 ;
87
108
@@ -113,31 +134,31 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
113
134
114
135
dev_dbg (dev , "Registering port %d\n" , port_num );
115
136
116
- cap = devm_kzalloc (dev , sizeof (* cap ), GFP_KERNEL );
117
- if (!cap ) {
137
+ cros_port = devm_kzalloc (dev , sizeof (* cros_port ), GFP_KERNEL );
138
+ if (!cros_port ) {
118
139
ret = - ENOMEM ;
119
140
goto unregister_ports ;
120
141
}
121
142
122
- typec -> caps [port_num ] = cap ;
143
+ typec -> ports [port_num ] = cros_port ;
144
+ cap = & cros_port -> caps ;
123
145
124
146
ret = cros_typec_parse_port_props (cap , fwnode , dev );
125
147
if (ret < 0 )
126
148
goto unregister_ports ;
127
149
128
- typec -> ports [ port_num ] = typec_register_port (dev , cap );
129
- if (IS_ERR (typec -> ports [ port_num ] )) {
150
+ cros_port -> port = typec_register_port (dev , cap );
151
+ if (IS_ERR (cros_port -> port )) {
130
152
dev_err (dev , "Failed to register port %d\n" , port_num );
131
- ret = PTR_ERR (typec -> ports [ port_num ] );
153
+ ret = PTR_ERR (cros_port -> port );
132
154
goto unregister_ports ;
133
155
}
134
156
}
135
157
136
158
return 0 ;
137
159
138
160
unregister_ports :
139
- for (i = 0 ; i < typec -> num_ports ; i ++ )
140
- typec_unregister_port (typec -> ports [i ]);
161
+ cros_unregister_ports (typec );
141
162
return ret ;
142
163
}
143
164
@@ -172,10 +193,34 @@ static int cros_typec_ec_command(struct cros_typec_data *typec,
172
193
return ret ;
173
194
}
174
195
196
+ static int cros_typec_add_partner (struct cros_typec_data * typec , int port_num ,
197
+ bool pd_en )
198
+ {
199
+ struct cros_typec_port * port = typec -> ports [port_num ];
200
+ struct typec_partner_desc p_desc = {
201
+ .usb_pd = pd_en ,
202
+ };
203
+ int ret = 0 ;
204
+
205
+ /*
206
+ * Fill an initial PD identity, which will then be updated with info
207
+ * from the EC.
208
+ */
209
+ p_desc .identity = & port -> p_identity ;
210
+
211
+ port -> partner = typec_register_partner (port -> port , & p_desc );
212
+ if (IS_ERR (port -> partner )) {
213
+ ret = PTR_ERR (port -> partner );
214
+ port -> partner = NULL ;
215
+ }
216
+
217
+ return ret ;
218
+ }
219
+
175
220
static void cros_typec_set_port_params_v0 (struct cros_typec_data * typec ,
176
221
int port_num , struct ec_response_usb_pd_control * resp )
177
222
{
178
- struct typec_port * port = typec -> ports [port_num ];
223
+ struct typec_port * port = typec -> ports [port_num ]-> port ;
179
224
enum typec_orientation polarity ;
180
225
181
226
if (!resp -> enabled )
@@ -192,8 +237,10 @@ static void cros_typec_set_port_params_v0(struct cros_typec_data *typec,
192
237
static void cros_typec_set_port_params_v1 (struct cros_typec_data * typec ,
193
238
int port_num , struct ec_response_usb_pd_control_v1 * resp )
194
239
{
195
- struct typec_port * port = typec -> ports [port_num ];
240
+ struct typec_port * port = typec -> ports [port_num ]-> port ;
196
241
enum typec_orientation polarity ;
242
+ bool pd_en ;
243
+ int ret ;
197
244
198
245
if (!(resp -> enabled & PD_CTRL_RESP_ENABLED_CONNECTED ))
199
246
polarity = TYPEC_ORIENTATION_NONE ;
@@ -208,6 +255,25 @@ static void cros_typec_set_port_params_v1(struct cros_typec_data *typec,
208
255
TYPEC_SOURCE : TYPEC_SINK );
209
256
typec_set_vconn_role (port , resp -> role & PD_CTRL_RESP_ROLE_VCONN ?
210
257
TYPEC_SOURCE : TYPEC_SINK );
258
+
259
+ /* Register/remove partners when a connect/disconnect occurs. */
260
+ if (resp -> enabled & PD_CTRL_RESP_ENABLED_CONNECTED ) {
261
+ if (typec -> ports [port_num ]-> partner )
262
+ return ;
263
+
264
+ pd_en = resp -> enabled & PD_CTRL_RESP_ENABLED_PD_CAPABLE ;
265
+ ret = cros_typec_add_partner (typec , port_num , pd_en );
266
+ if (ret )
267
+ dev_warn (typec -> dev ,
268
+ "Failed to register partner on port: %d\n" ,
269
+ port_num );
270
+ } else {
271
+ if (!typec -> ports [port_num ]-> partner )
272
+ return ;
273
+
274
+ typec_unregister_partner (typec -> ports [port_num ]-> partner );
275
+ typec -> ports [port_num ]-> partner = NULL ;
276
+ }
211
277
}
212
278
213
279
static int cros_typec_port_update (struct cros_typec_data * typec , int port_num )
@@ -272,6 +338,22 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
272
338
return 0 ;
273
339
}
274
340
341
+ static int cros_ec_typec_event (struct notifier_block * nb ,
342
+ unsigned long host_event , void * _notify )
343
+ {
344
+ struct cros_typec_data * typec = container_of (nb , struct cros_typec_data ,
345
+ nb );
346
+ int ret , i ;
347
+
348
+ for (i = 0 ; i < typec -> num_ports ; i ++ ) {
349
+ ret = cros_typec_port_update (typec , i );
350
+ if (ret < 0 )
351
+ dev_warn (typec -> dev , "Update failed for port: %d\n" , i );
352
+ }
353
+
354
+ return NOTIFY_OK ;
355
+ }
356
+
275
357
#ifdef CONFIG_ACPI
276
358
static const struct acpi_device_id cros_typec_acpi_id [] = {
277
359
{ "GOOG0014" , 0 },
@@ -332,12 +414,15 @@ static int cros_typec_probe(struct platform_device *pdev)
332
414
goto unregister_ports ;
333
415
}
334
416
417
+ typec -> nb .notifier_call = cros_ec_typec_event ;
418
+ ret = cros_usbpd_register_notify (& typec -> nb );
419
+ if (ret < 0 )
420
+ goto unregister_ports ;
421
+
335
422
return 0 ;
336
423
337
424
unregister_ports :
338
- for (i = 0 ; i < typec -> num_ports ; i ++ )
339
- if (typec -> ports [i ])
340
- typec_unregister_port (typec -> ports [i ]);
425
+ cros_unregister_ports (typec );
341
426
return ret ;
342
427
}
343
428
0 commit comments