hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/usb/typec/class.c
....@@ -9,9 +9,10 @@
99 #include <linux/device.h>
1010 #include <linux/module.h>
1111 #include <linux/mutex.h>
12
-#include <linux/of.h>
1312 #include <linux/property.h>
1413 #include <linux/slab.h>
14
+#include <linux/usb/pd_vdo.h>
15
+#include <linux/android_kabi.h>
1516
1617 #include "bus.h"
1718
....@@ -19,6 +20,8 @@
1920 struct device dev;
2021 enum typec_plug_index index;
2122 struct ida mode_ids;
23
+ int num_altmodes;
24
+ ANDROID_KABI_RESERVE(1);
2225 };
2326
2427 struct typec_cable {
....@@ -26,6 +29,8 @@
2629 enum typec_plug_type type;
2730 struct usb_pd_identity *identity;
2831 unsigned int active:1;
32
+ u16 pd_revision; /* 0300H = "3.0" */
33
+ ANDROID_KABI_RESERVE(1);
2934 };
3035
3136 struct typec_partner {
....@@ -34,6 +39,10 @@
3439 struct usb_pd_identity *identity;
3540 enum typec_accessory accessory;
3641 struct ida mode_ids;
42
+ int num_altmodes;
43
+ u16 pd_revision; /* 0300H = "3.0" */
44
+ enum usb_pd_svdm_ver svdm_version;
45
+ ANDROID_KABI_RESERVE(1);
3746 };
3847
3948 struct typec_port {
....@@ -54,6 +63,8 @@
5463 struct typec_mux *mux;
5564
5665 const struct typec_capability *cap;
66
+ const struct typec_operations *ops;
67
+ ANDROID_KABI_RESERVE(1);
5768 };
5869
5970 #define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
....@@ -81,6 +92,29 @@
8192 [TYPEC_ACCESSORY_DEBUG] = "debug",
8293 };
8394
95
+/* Product types defined in USB PD Specification R3.0 V2.0 */
96
+static const char * const product_type_ufp[8] = {
97
+ [IDH_PTYPE_NOT_UFP] = "not_ufp",
98
+ [IDH_PTYPE_HUB] = "hub",
99
+ [IDH_PTYPE_PERIPH] = "peripheral",
100
+ [IDH_PTYPE_PSD] = "psd",
101
+ [IDH_PTYPE_AMA] = "ama",
102
+};
103
+
104
+static const char * const product_type_dfp[8] = {
105
+ [IDH_PTYPE_NOT_DFP] = "not_dfp",
106
+ [IDH_PTYPE_DFP_HUB] = "hub",
107
+ [IDH_PTYPE_DFP_HOST] = "host",
108
+ [IDH_PTYPE_DFP_PB] = "power_brick",
109
+};
110
+
111
+static const char * const product_type_cable[8] = {
112
+ [IDH_PTYPE_NOT_CABLE] = "not_cable",
113
+ [IDH_PTYPE_PCABLE] = "passive",
114
+ [IDH_PTYPE_ACABLE] = "active",
115
+ [IDH_PTYPE_VPD] = "vpd",
116
+};
117
+
84118 static struct usb_pd_identity *get_pd_identity(struct device *dev)
85119 {
86120 if (is_typec_partner(dev)) {
....@@ -93,6 +127,32 @@
93127 return cable->identity;
94128 }
95129 return NULL;
130
+}
131
+
132
+static const char *get_pd_product_type(struct device *dev)
133
+{
134
+ struct typec_port *port = to_typec_port(dev->parent);
135
+ struct usb_pd_identity *id = get_pd_identity(dev);
136
+ const char *ptype = NULL;
137
+
138
+ if (is_typec_partner(dev)) {
139
+ if (!id)
140
+ return NULL;
141
+
142
+ if (port->data_role == TYPEC_HOST)
143
+ ptype = product_type_ufp[PD_IDH_PTYPE(id->id_header)];
144
+ else
145
+ ptype = product_type_dfp[PD_IDH_DFP_PTYPE(id->id_header)];
146
+ } else if (is_typec_cable(dev)) {
147
+ if (id)
148
+ ptype = product_type_cable[PD_IDH_PTYPE(id->id_header)];
149
+ else
150
+ ptype = to_typec_cable(dev)->active ?
151
+ product_type_cable[IDH_PTYPE_ACABLE] :
152
+ product_type_cable[IDH_PTYPE_PCABLE];
153
+ }
154
+
155
+ return ptype;
96156 }
97157
98158 static ssize_t id_header_show(struct device *dev, struct device_attribute *attr,
....@@ -122,10 +182,40 @@
122182 }
123183 static DEVICE_ATTR_RO(product);
124184
185
+static ssize_t product_type_vdo1_show(struct device *dev, struct device_attribute *attr,
186
+ char *buf)
187
+{
188
+ struct usb_pd_identity *id = get_pd_identity(dev);
189
+
190
+ return sysfs_emit(buf, "0x%08x\n", id->vdo[0]);
191
+}
192
+static DEVICE_ATTR_RO(product_type_vdo1);
193
+
194
+static ssize_t product_type_vdo2_show(struct device *dev, struct device_attribute *attr,
195
+ char *buf)
196
+{
197
+ struct usb_pd_identity *id = get_pd_identity(dev);
198
+
199
+ return sysfs_emit(buf, "0x%08x\n", id->vdo[1]);
200
+}
201
+static DEVICE_ATTR_RO(product_type_vdo2);
202
+
203
+static ssize_t product_type_vdo3_show(struct device *dev, struct device_attribute *attr,
204
+ char *buf)
205
+{
206
+ struct usb_pd_identity *id = get_pd_identity(dev);
207
+
208
+ return sysfs_emit(buf, "0x%08x\n", id->vdo[2]);
209
+}
210
+static DEVICE_ATTR_RO(product_type_vdo3);
211
+
125212 static struct attribute *usb_pd_id_attrs[] = {
126213 &dev_attr_id_header.attr,
127214 &dev_attr_cert_stat.attr,
128215 &dev_attr_product.attr,
216
+ &dev_attr_product_type_vdo1.attr,
217
+ &dev_attr_product_type_vdo2.attr,
218
+ &dev_attr_product_type_vdo3.attr,
129219 NULL
130220 };
131221
....@@ -139,12 +229,53 @@
139229 NULL,
140230 };
141231
232
+static void typec_product_type_notify(struct device *dev)
233
+{
234
+ char *envp[2] = { };
235
+ const char *ptype;
236
+
237
+ ptype = get_pd_product_type(dev);
238
+ if (!ptype)
239
+ return;
240
+
241
+ sysfs_notify(&dev->kobj, NULL, "type");
242
+
243
+ envp[0] = kasprintf(GFP_KERNEL, "PRODUCT_TYPE=%s", ptype);
244
+ if (!envp[0])
245
+ return;
246
+
247
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
248
+ kfree(envp[0]);
249
+}
250
+
142251 static void typec_report_identity(struct device *dev)
143252 {
144253 sysfs_notify(&dev->kobj, "identity", "id_header");
145254 sysfs_notify(&dev->kobj, "identity", "cert_stat");
146255 sysfs_notify(&dev->kobj, "identity", "product");
256
+ sysfs_notify(&dev->kobj, "identity", "product_type_vdo1");
257
+ sysfs_notify(&dev->kobj, "identity", "product_type_vdo2");
258
+ sysfs_notify(&dev->kobj, "identity", "product_type_vdo3");
259
+ typec_product_type_notify(dev);
147260 }
261
+
262
+static ssize_t
263
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
264
+{
265
+ const char *ptype;
266
+
267
+ ptype = get_pd_product_type(dev);
268
+ if (!ptype)
269
+ return 0;
270
+
271
+ return sysfs_emit(buf, "%s\n", ptype);
272
+}
273
+static DEVICE_ATTR_RO(type);
274
+
275
+static ssize_t usb_power_delivery_revision_show(struct device *dev,
276
+ struct device_attribute *attr,
277
+ char *buf);
278
+static DEVICE_ATTR_RO(usb_power_delivery_revision);
148279
149280 /* ------------------------------------------------------------------------- */
150281 /* Alternate Modes */
....@@ -205,81 +336,6 @@
205336 }
206337 put_device(&adev->dev);
207338 }
208
-
209
-static int typec_port_fwnode_match(struct device *dev, const void *fwnode)
210
-{
211
- return dev_fwnode(dev) == fwnode;
212
-}
213
-
214
-static int typec_port_name_match(struct device *dev, const void *name)
215
-{
216
- return !strcmp((const char *)name, dev_name(dev));
217
-}
218
-
219
-static void *typec_port_match(struct device_connection *con, int ep, void *data)
220
-{
221
- struct device *dev;
222
-
223
- /*
224
- * FIXME: Check does the fwnode supports the requested SVID. If it does
225
- * we need to return ERR_PTR(-PROBE_DEFER) when there is no device.
226
- */
227
- if (con->fwnode)
228
- return class_find_device(typec_class, NULL, con->fwnode,
229
- typec_port_fwnode_match);
230
-
231
- dev = class_find_device(typec_class, NULL, con->endpoint[ep],
232
- typec_port_name_match);
233
-
234
- return dev ? dev : ERR_PTR(-EPROBE_DEFER);
235
-}
236
-
237
-struct typec_altmode *
238
-typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
239
- struct notifier_block *nb)
240
-{
241
- struct typec_device_id id = { svid, mode, };
242
- struct device *altmode_dev;
243
- struct device *port_dev;
244
- struct altmode *altmode;
245
- int ret;
246
-
247
- /* Find the port linked to the caller */
248
- port_dev = device_connection_find_match(dev, NULL, NULL,
249
- typec_port_match);
250
- if (IS_ERR_OR_NULL(port_dev))
251
- return port_dev ? ERR_CAST(port_dev) : ERR_PTR(-ENODEV);
252
-
253
- /* Find the altmode with matching svid */
254
- altmode_dev = device_find_child(port_dev, &id, altmode_match);
255
-
256
- put_device(port_dev);
257
-
258
- if (!altmode_dev)
259
- return ERR_PTR(-ENODEV);
260
-
261
- altmode = to_altmode(to_typec_altmode(altmode_dev));
262
-
263
- /* Register notifier */
264
- ret = blocking_notifier_chain_register(&altmode->nh, nb);
265
- if (ret) {
266
- put_device(altmode_dev);
267
- return ERR_PTR(ret);
268
- }
269
-
270
- return &altmode->adev;
271
-}
272
-EXPORT_SYMBOL_GPL(typec_altmode_register_notifier);
273
-
274
-void typec_altmode_unregister_notifier(struct typec_altmode *adev,
275
- struct notifier_block *nb)
276
-{
277
- struct altmode *altmode = to_altmode(adev);
278
-
279
- blocking_notifier_chain_unregister(&altmode->nh, nb);
280
- put_device(&adev->dev);
281
-}
282
-EXPORT_SYMBOL_GPL(typec_altmode_unregister_notifier);
283339
284340 /**
285341 * typec_altmode_update_active - Report Enter/Exit mode
....@@ -444,7 +500,28 @@
444500 &dev_attr_vdo.attr,
445501 NULL
446502 };
447
-ATTRIBUTE_GROUPS(typec_altmode);
503
+
504
+static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
505
+ struct attribute *attr, int n)
506
+{
507
+ struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
508
+
509
+ if (attr == &dev_attr_active.attr)
510
+ if (!adev->ops || !adev->ops->activate)
511
+ return 0444;
512
+
513
+ return attr->mode;
514
+}
515
+
516
+static const struct attribute_group typec_altmode_group = {
517
+ .is_visible = typec_altmode_attr_is_visible,
518
+ .attrs = typec_altmode_attrs,
519
+};
520
+
521
+static const struct attribute_group *typec_altmode_groups[] = {
522
+ &typec_altmode_group,
523
+ NULL
524
+};
448525
449526 static int altmode_id_get(struct device *dev)
450527 {
....@@ -531,14 +608,16 @@
531608 dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
532609
533610 /* Link partners and plugs with the ports */
534
- if (is_port)
535
- BLOCKING_INIT_NOTIFIER_HEAD(&alt->nh);
536
- else
611
+ if (!is_port)
537612 typec_altmode_set_partner(alt);
538613
539614 /* The partners are bind to drivers */
540615 if (is_typec_partner(parent))
541616 alt->adev.dev.bus = &typec_bus;
617
+
618
+ /* Plug alt modes need a class to generate udev events. */
619
+ if (is_typec_plug(parent))
620
+ alt->adev.dev.class = typec_class;
542621
543622 ret = device_register(&alt->adev.dev);
544623 if (ret) {
....@@ -590,12 +669,61 @@
590669 }
591670 static DEVICE_ATTR_RO(supports_usb_power_delivery);
592671
672
+static ssize_t number_of_alternate_modes_show(struct device *dev, struct device_attribute *attr,
673
+ char *buf)
674
+{
675
+ struct typec_partner *partner;
676
+ struct typec_plug *plug;
677
+ int num_altmodes;
678
+
679
+ if (is_typec_partner(dev)) {
680
+ partner = to_typec_partner(dev);
681
+ num_altmodes = partner->num_altmodes;
682
+ } else if (is_typec_plug(dev)) {
683
+ plug = to_typec_plug(dev);
684
+ num_altmodes = plug->num_altmodes;
685
+ } else {
686
+ return 0;
687
+ }
688
+
689
+ return sysfs_emit(buf, "%d\n", num_altmodes);
690
+}
691
+static DEVICE_ATTR_RO(number_of_alternate_modes);
692
+
593693 static struct attribute *typec_partner_attrs[] = {
594694 &dev_attr_accessory_mode.attr,
595695 &dev_attr_supports_usb_power_delivery.attr,
696
+ &dev_attr_number_of_alternate_modes.attr,
697
+ &dev_attr_type.attr,
698
+ &dev_attr_usb_power_delivery_revision.attr,
596699 NULL
597700 };
598
-ATTRIBUTE_GROUPS(typec_partner);
701
+
702
+static umode_t typec_partner_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
703
+{
704
+ struct typec_partner *partner = to_typec_partner(kobj_to_dev(kobj));
705
+
706
+ if (attr == &dev_attr_number_of_alternate_modes.attr) {
707
+ if (partner->num_altmodes < 0)
708
+ return 0;
709
+ }
710
+
711
+ if (attr == &dev_attr_type.attr)
712
+ if (!get_pd_product_type(kobj_to_dev(kobj)))
713
+ return 0;
714
+
715
+ return attr->mode;
716
+}
717
+
718
+static const struct attribute_group typec_partner_group = {
719
+ .is_visible = typec_partner_attr_is_visible,
720
+ .attrs = typec_partner_attrs
721
+};
722
+
723
+static const struct attribute_group *typec_partner_groups[] = {
724
+ &typec_partner_group,
725
+ NULL
726
+};
599727
600728 static void typec_partner_release(struct device *dev)
601729 {
....@@ -629,6 +757,61 @@
629757 EXPORT_SYMBOL_GPL(typec_partner_set_identity);
630758
631759 /**
760
+ * typec_partner_set_pd_revision - Set the PD revision supported by the partner
761
+ * @partner: The partner to be updated.
762
+ * @pd_revision: USB Power Delivery Specification Revision supported by partner
763
+ *
764
+ * This routine is used to report that the PD revision of the port partner has
765
+ * become available.
766
+ */
767
+void typec_partner_set_pd_revision(struct typec_partner *partner, u16 pd_revision)
768
+{
769
+ if (partner->pd_revision == pd_revision)
770
+ return;
771
+
772
+ partner->pd_revision = pd_revision;
773
+ sysfs_notify(&partner->dev.kobj, NULL, "usb_power_delivery_revision");
774
+ if (pd_revision != 0 && !partner->usb_pd) {
775
+ partner->usb_pd = 1;
776
+ sysfs_notify(&partner->dev.kobj, NULL,
777
+ "supports_usb_power_delivery");
778
+ }
779
+ kobject_uevent(&partner->dev.kobj, KOBJ_CHANGE);
780
+}
781
+EXPORT_SYMBOL_GPL(typec_partner_set_pd_revision);
782
+
783
+/**
784
+ * typec_partner_set_num_altmodes - Set the number of available partner altmodes
785
+ * @partner: The partner to be updated.
786
+ * @num_altmodes: The number of altmodes we want to specify as available.
787
+ *
788
+ * This routine is used to report the number of alternate modes supported by the
789
+ * partner. This value is *not* enforced in alternate mode registration routines.
790
+ *
791
+ * @partner.num_altmodes is set to -1 on partner registration, denoting that
792
+ * a valid value has not been set for it yet.
793
+ *
794
+ * Returns 0 on success or negative error number on failure.
795
+ */
796
+int typec_partner_set_num_altmodes(struct typec_partner *partner, int num_altmodes)
797
+{
798
+ int ret;
799
+
800
+ if (num_altmodes < 0)
801
+ return -EINVAL;
802
+
803
+ partner->num_altmodes = num_altmodes;
804
+ ret = sysfs_update_group(&partner->dev.kobj, &typec_partner_group);
805
+ if (ret < 0)
806
+ return ret;
807
+
808
+ sysfs_notify(&partner->dev.kobj, NULL, "number_of_alternate_modes");
809
+
810
+ return 0;
811
+}
812
+EXPORT_SYMBOL_GPL(typec_partner_set_num_altmodes);
813
+
814
+/**
632815 * typec_partner_register_altmode - Register USB Type-C Partner Alternate Mode
633816 * @partner: USB Type-C Partner that supports the alternate mode
634817 * @desc: Description of the alternate mode
....@@ -638,7 +821,7 @@
638821 * SVID listed in response to Discover Modes command need to be listed in an
639822 * array in @desc.
640823 *
641
- * Returns handle to the alternate mode on success or NULL on failure.
824
+ * Returns handle to the alternate mode on success or ERR_PTR on failure.
642825 */
643826 struct typec_altmode *
644827 typec_partner_register_altmode(struct typec_partner *partner,
....@@ -647,6 +830,20 @@
647830 return typec_register_altmode(&partner->dev, desc);
648831 }
649832 EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
833
+
834
+/**
835
+ * typec_partner_set_svdm_version - Set negotiated Structured VDM (SVDM) Version
836
+ * @partner: USB Type-C Partner that supports SVDM
837
+ * @svdm_version: Negotiated SVDM Version
838
+ *
839
+ * This routine is used to save the negotiated SVDM Version.
840
+ */
841
+void typec_partner_set_svdm_version(struct typec_partner *partner,
842
+ enum usb_pd_svdm_ver svdm_version)
843
+{
844
+ partner->svdm_version = svdm_version;
845
+}
846
+EXPORT_SYMBOL_GPL(typec_partner_set_svdm_version);
650847
651848 /**
652849 * typec_register_partner - Register a USB Type-C Partner
....@@ -670,6 +867,9 @@
670867 ida_init(&partner->mode_ids);
671868 partner->usb_pd = desc->usb_pd;
672869 partner->accessory = desc->accessory;
870
+ partner->num_altmodes = -1;
871
+ partner->pd_revision = desc->pd_revision;
872
+ partner->svdm_version = port->cap->svdm_version;
673873
674874 if (desc->identity) {
675875 /*
....@@ -720,10 +920,69 @@
720920 kfree(plug);
721921 }
722922
923
+static struct attribute *typec_plug_attrs[] = {
924
+ &dev_attr_number_of_alternate_modes.attr,
925
+ NULL
926
+};
927
+
928
+static umode_t typec_plug_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
929
+{
930
+ struct typec_plug *plug = to_typec_plug(kobj_to_dev(kobj));
931
+
932
+ if (attr == &dev_attr_number_of_alternate_modes.attr) {
933
+ if (plug->num_altmodes < 0)
934
+ return 0;
935
+ }
936
+
937
+ return attr->mode;
938
+}
939
+
940
+static const struct attribute_group typec_plug_group = {
941
+ .is_visible = typec_plug_attr_is_visible,
942
+ .attrs = typec_plug_attrs
943
+};
944
+
945
+static const struct attribute_group *typec_plug_groups[] = {
946
+ &typec_plug_group,
947
+ NULL
948
+};
949
+
723950 static const struct device_type typec_plug_dev_type = {
724951 .name = "typec_plug",
952
+ .groups = typec_plug_groups,
725953 .release = typec_plug_release,
726954 };
955
+
956
+/**
957
+ * typec_plug_set_num_altmodes - Set the number of available plug altmodes
958
+ * @plug: The plug to be updated.
959
+ * @num_altmodes: The number of altmodes we want to specify as available.
960
+ *
961
+ * This routine is used to report the number of alternate modes supported by the
962
+ * plug. This value is *not* enforced in alternate mode registration routines.
963
+ *
964
+ * @plug.num_altmodes is set to -1 on plug registration, denoting that
965
+ * a valid value has not been set for it yet.
966
+ *
967
+ * Returns 0 on success or negative error number on failure.
968
+ */
969
+int typec_plug_set_num_altmodes(struct typec_plug *plug, int num_altmodes)
970
+{
971
+ int ret;
972
+
973
+ if (num_altmodes < 0)
974
+ return -EINVAL;
975
+
976
+ plug->num_altmodes = num_altmodes;
977
+ ret = sysfs_update_group(&plug->dev.kobj, &typec_plug_group);
978
+ if (ret < 0)
979
+ return ret;
980
+
981
+ sysfs_notify(&plug->dev.kobj, NULL, "number_of_alternate_modes");
982
+
983
+ return 0;
984
+}
985
+EXPORT_SYMBOL_GPL(typec_plug_set_num_altmodes);
727986
728987 /**
729988 * typec_plug_register_altmode - Register USB Type-C Cable Plug Alternate Mode
....@@ -770,6 +1029,7 @@
7701029 sprintf(name, "plug%d", desc->index);
7711030
7721031 ida_init(&plug->mode_ids);
1032
+ plug->num_altmodes = -1;
7731033 plug->index = desc->index;
7741034 plug->dev.class = typec_class;
7751035 plug->dev.parent = &cable->dev;
....@@ -802,15 +1062,6 @@
8021062
8031063 /* Type-C Cables */
8041064
805
-static ssize_t
806
-type_show(struct device *dev, struct device_attribute *attr, char *buf)
807
-{
808
- struct typec_cable *cable = to_typec_cable(dev);
809
-
810
- return sprintf(buf, "%s\n", cable->active ? "active" : "passive");
811
-}
812
-static DEVICE_ATTR_RO(type);
813
-
8141065 static const char * const typec_plug_types[] = {
8151066 [USB_PLUG_NONE] = "unknown",
8161067 [USB_PLUG_TYPE_A] = "type-a",
....@@ -831,6 +1082,7 @@
8311082 static struct attribute *typec_cable_attrs[] = {
8321083 &dev_attr_type.attr,
8331084 &dev_attr_plug_type.attr,
1085
+ &dev_attr_usb_power_delivery_revision.attr,
8341086 NULL
8351087 };
8361088 ATTRIBUTE_GROUPS(typec_cable);
....@@ -847,6 +1099,52 @@
8471099 .groups = typec_cable_groups,
8481100 .release = typec_cable_release,
8491101 };
1102
+
1103
+static int cable_match(struct device *dev, void *data)
1104
+{
1105
+ return is_typec_cable(dev);
1106
+}
1107
+
1108
+/**
1109
+ * typec_cable_get - Get a reference to the USB Type-C cable
1110
+ * @port: The USB Type-C Port the cable is connected to
1111
+ *
1112
+ * The caller must decrement the reference count with typec_cable_put() after
1113
+ * use.
1114
+ */
1115
+struct typec_cable *typec_cable_get(struct typec_port *port)
1116
+{
1117
+ struct device *dev;
1118
+
1119
+ dev = device_find_child(&port->dev, NULL, cable_match);
1120
+ if (!dev)
1121
+ return NULL;
1122
+
1123
+ return to_typec_cable(dev);
1124
+}
1125
+EXPORT_SYMBOL_GPL(typec_cable_get);
1126
+
1127
+/**
1128
+ * typec_cable_put - Decrement the reference count on USB Type-C cable
1129
+ * @cable: The USB Type-C cable
1130
+ */
1131
+void typec_cable_put(struct typec_cable *cable)
1132
+{
1133
+ put_device(&cable->dev);
1134
+}
1135
+EXPORT_SYMBOL_GPL(typec_cable_put);
1136
+
1137
+/**
1138
+ * typec_cable_is_active - Check is the USB Type-C cable active or passive
1139
+ * @cable: The USB Type-C Cable
1140
+ *
1141
+ * Return 1 if the cable is active or 0 if it's passive.
1142
+ */
1143
+int typec_cable_is_active(struct typec_cable *cable)
1144
+{
1145
+ return cable->active;
1146
+}
1147
+EXPORT_SYMBOL_GPL(typec_cable_is_active);
8501148
8511149 /**
8521150 * typec_cable_set_identity - Report result from Discover Identity command
....@@ -887,6 +1185,7 @@
8871185
8881186 cable->type = desc->type;
8891187 cable->active = desc->active;
1188
+ cable->pd_revision = desc->pd_revision;
8901189
8911190 if (desc->identity) {
8921191 /*
....@@ -929,6 +1228,12 @@
9291228 /* ------------------------------------------------------------------------- */
9301229 /* USB Type-C ports */
9311230
1231
+static const char * const typec_orientations[] = {
1232
+ [TYPEC_ORIENTATION_NONE] = "unknown",
1233
+ [TYPEC_ORIENTATION_NORMAL] = "normal",
1234
+ [TYPEC_ORIENTATION_REVERSE] = "reverse",
1235
+};
1236
+
9321237 static const char * const typec_roles[] = {
9331238 [TYPEC_SINK] = "sink",
9341239 [TYPEC_SOURCE] = "source",
....@@ -970,7 +1275,7 @@
9701275 return -EOPNOTSUPP;
9711276 }
9721277
973
- if (!port->cap->try_role) {
1278
+ if (!port->ops || !port->ops->try_role) {
9741279 dev_dbg(dev, "Setting preferred role not supported\n");
9751280 return -EOPNOTSUPP;
9761281 }
....@@ -983,7 +1288,7 @@
9831288 return -EINVAL;
9841289 }
9851290
986
- ret = port->cap->try_role(port->cap, role);
1291
+ ret = port->ops->try_role(port, role);
9871292 if (ret)
9881293 return ret;
9891294
....@@ -1014,7 +1319,7 @@
10141319 struct typec_port *port = to_typec_port(dev);
10151320 int ret;
10161321
1017
- if (!port->cap->dr_set) {
1322
+ if (!port->ops || !port->ops->dr_set) {
10181323 dev_dbg(dev, "data role swapping not supported\n");
10191324 return -EOPNOTSUPP;
10201325 }
....@@ -1029,7 +1334,7 @@
10291334 goto unlock_and_ret;
10301335 }
10311336
1032
- ret = port->cap->dr_set(port->cap, ret);
1337
+ ret = port->ops->dr_set(port, ret);
10331338 if (ret)
10341339 goto unlock_and_ret;
10351340
....@@ -1059,12 +1364,7 @@
10591364 struct typec_port *port = to_typec_port(dev);
10601365 int ret;
10611366
1062
- if (!port->cap->pd_revision) {
1063
- dev_dbg(dev, "USB Power Delivery not supported\n");
1064
- return -EOPNOTSUPP;
1065
- }
1066
-
1067
- if (!port->cap->pr_set) {
1367
+ if (!port->ops || !port->ops->pr_set) {
10681368 dev_dbg(dev, "power role swapping not supported\n");
10691369 return -EOPNOTSUPP;
10701370 }
....@@ -1086,7 +1386,7 @@
10861386 goto unlock_and_ret;
10871387 }
10881388
1089
- ret = port->cap->pr_set(port->cap, ret);
1389
+ ret = port->ops->pr_set(port, ret);
10901390 if (ret)
10911391 goto unlock_and_ret;
10921392
....@@ -1117,7 +1417,8 @@
11171417 int ret;
11181418 enum typec_port_type type;
11191419
1120
- if (!port->cap->port_type_set || port->cap->type != TYPEC_PORT_DRP) {
1420
+ if (port->cap->type != TYPEC_PORT_DRP ||
1421
+ !port->ops || !port->ops->port_type_set) {
11211422 dev_dbg(dev, "changing port type not supported\n");
11221423 return -EOPNOTSUPP;
11231424 }
....@@ -1134,7 +1435,7 @@
11341435 goto unlock_and_ret;
11351436 }
11361437
1137
- ret = port->cap->port_type_set(port->cap, type);
1438
+ ret = port->ops->port_type_set(port, type);
11381439 if (ret)
11391440 goto unlock_and_ret;
11401441
....@@ -1190,7 +1491,7 @@
11901491 return -EOPNOTSUPP;
11911492 }
11921493
1193
- if (!port->cap->vconn_set) {
1494
+ if (!port->ops || !port->ops->vconn_set) {
11941495 dev_dbg(dev, "VCONN swapping not supported\n");
11951496 return -EOPNOTSUPP;
11961497 }
....@@ -1199,7 +1500,7 @@
11991500 if (ret)
12001501 return ret;
12011502
1202
- ret = port->cap->vconn_set(port->cap, (enum typec_role)source);
1503
+ ret = port->ops->vconn_set(port, (enum typec_role)source);
12031504 if (ret)
12041505 return ret;
12051506
....@@ -1254,11 +1555,33 @@
12541555 struct device_attribute *attr,
12551556 char *buf)
12561557 {
1257
- struct typec_port *p = to_typec_port(dev);
1558
+ u16 rev = 0;
12581559
1259
- return sprintf(buf, "%d\n", (p->cap->pd_revision >> 8) & 0xff);
1560
+ if (is_typec_partner(dev)) {
1561
+ struct typec_partner *partner = to_typec_partner(dev);
1562
+
1563
+ rev = partner->pd_revision;
1564
+ } else if (is_typec_cable(dev)) {
1565
+ struct typec_cable *cable = to_typec_cable(dev);
1566
+
1567
+ rev = cable->pd_revision;
1568
+ } else if (is_typec_port(dev)) {
1569
+ struct typec_port *p = to_typec_port(dev);
1570
+
1571
+ rev = p->cap->pd_revision;
1572
+ }
1573
+ return sysfs_emit(buf, "%d.%d\n", (rev >> 8) & 0xff, (rev >> 4) & 0xf);
12601574 }
1261
-static DEVICE_ATTR_RO(usb_power_delivery_revision);
1575
+
1576
+static ssize_t orientation_show(struct device *dev,
1577
+ struct device_attribute *attr,
1578
+ char *buf)
1579
+{
1580
+ struct typec_port *port = to_typec_port(dev);
1581
+
1582
+ return sprintf(buf, "%s\n", typec_orientations[port->orientation]);
1583
+}
1584
+static DEVICE_ATTR_RO(orientation);
12621585
12631586 static struct attribute *typec_attrs[] = {
12641587 &dev_attr_data_role.attr,
....@@ -1270,9 +1593,54 @@
12701593 &dev_attr_usb_typec_revision.attr,
12711594 &dev_attr_vconn_source.attr,
12721595 &dev_attr_port_type.attr,
1596
+ &dev_attr_orientation.attr,
12731597 NULL,
12741598 };
1275
-ATTRIBUTE_GROUPS(typec);
1599
+
1600
+static umode_t typec_attr_is_visible(struct kobject *kobj,
1601
+ struct attribute *attr, int n)
1602
+{
1603
+ struct typec_port *port = to_typec_port(kobj_to_dev(kobj));
1604
+
1605
+ if (attr == &dev_attr_data_role.attr) {
1606
+ if (port->cap->data != TYPEC_PORT_DRD ||
1607
+ !port->ops || !port->ops->dr_set)
1608
+ return 0444;
1609
+ } else if (attr == &dev_attr_power_role.attr) {
1610
+ if (port->cap->type != TYPEC_PORT_DRP ||
1611
+ !port->ops || !port->ops->pr_set)
1612
+ return 0444;
1613
+ } else if (attr == &dev_attr_vconn_source.attr) {
1614
+ if (!port->cap->pd_revision ||
1615
+ !port->ops || !port->ops->vconn_set)
1616
+ return 0444;
1617
+ } else if (attr == &dev_attr_preferred_role.attr) {
1618
+ if (port->cap->type != TYPEC_PORT_DRP ||
1619
+ !port->ops || !port->ops->try_role)
1620
+ return 0444;
1621
+ } else if (attr == &dev_attr_port_type.attr) {
1622
+ if (!port->ops || !port->ops->port_type_set)
1623
+ return 0;
1624
+ if (port->cap->type != TYPEC_PORT_DRP)
1625
+ return 0444;
1626
+ } else if (attr == &dev_attr_orientation.attr) {
1627
+ if (port->cap->orientation_aware)
1628
+ return 0444;
1629
+ return 0;
1630
+ }
1631
+
1632
+ return attr->mode;
1633
+}
1634
+
1635
+static const struct attribute_group typec_group = {
1636
+ .is_visible = typec_attr_is_visible,
1637
+ .attrs = typec_attrs,
1638
+};
1639
+
1640
+static const struct attribute_group *typec_groups[] = {
1641
+ &typec_group,
1642
+ NULL
1643
+};
12761644
12771645 static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
12781646 {
....@@ -1293,6 +1661,7 @@
12931661 ida_destroy(&port->mode_ids);
12941662 typec_switch_put(port->sw);
12951663 typec_mux_put(port->mux);
1664
+ kfree(port->cap);
12961665 kfree(port);
12971666 }
12981667
....@@ -1306,6 +1675,11 @@
13061675 /* --------------------------------------- */
13071676 /* Driver callbacks to report role updates */
13081677
1678
+static int partner_match(struct device *dev, void *data)
1679
+{
1680
+ return is_typec_partner(dev);
1681
+}
1682
+
13091683 /**
13101684 * typec_set_data_role - Report data role change
13111685 * @port: The USB Type-C Port where the role was changed
....@@ -1315,12 +1689,23 @@
13151689 */
13161690 void typec_set_data_role(struct typec_port *port, enum typec_data_role role)
13171691 {
1692
+ struct device *partner_dev;
1693
+
13181694 if (port->data_role == role)
13191695 return;
13201696
13211697 port->data_role = role;
13221698 sysfs_notify(&port->dev.kobj, NULL, "data_role");
13231699 kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
1700
+
1701
+ partner_dev = device_find_child(&port->dev, NULL, partner_match);
1702
+ if (!partner_dev)
1703
+ return;
1704
+
1705
+ if (to_typec_partner(partner_dev)->identity)
1706
+ typec_product_type_notify(partner_dev);
1707
+
1708
+ put_device(partner_dev);
13241709 }
13251710 EXPORT_SYMBOL_GPL(typec_set_data_role);
13261711
....@@ -1361,11 +1746,6 @@
13611746 }
13621747 EXPORT_SYMBOL_GPL(typec_set_vconn_role);
13631748
1364
-static int partner_match(struct device *dev, void *data)
1365
-{
1366
- return is_typec_partner(dev);
1367
-}
1368
-
13691749 /**
13701750 * typec_set_pwr_opmode - Report changed power operation mode
13711751 * @port: The USB Type-C Port where the mode was changed
....@@ -1396,11 +1776,42 @@
13961776 partner->usb_pd = 1;
13971777 sysfs_notify(&partner_dev->kobj, NULL,
13981778 "supports_usb_power_delivery");
1779
+ kobject_uevent(&partner_dev->kobj, KOBJ_CHANGE);
13991780 }
14001781 put_device(partner_dev);
14011782 }
14021783 }
14031784 EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
1785
+
1786
+/**
1787
+ * typec_find_pwr_opmode - Get the typec power operation mode capability
1788
+ * @name: power operation mode string
1789
+ *
1790
+ * This routine is used to find the typec_pwr_opmode by its string @name.
1791
+ *
1792
+ * Returns typec_pwr_opmode if success, otherwise negative error code.
1793
+ */
1794
+int typec_find_pwr_opmode(const char *name)
1795
+{
1796
+ return match_string(typec_pwr_opmodes,
1797
+ ARRAY_SIZE(typec_pwr_opmodes), name);
1798
+}
1799
+EXPORT_SYMBOL_GPL(typec_find_pwr_opmode);
1800
+
1801
+/**
1802
+ * typec_find_orientation - Convert orientation string to enum typec_orientation
1803
+ * @name: Orientation string
1804
+ *
1805
+ * This routine is used to find the typec_orientation by its string name @name.
1806
+ *
1807
+ * Returns the orientation value on success, otherwise negative error code.
1808
+ */
1809
+int typec_find_orientation(const char *name)
1810
+{
1811
+ return match_string(typec_orientations, ARRAY_SIZE(typec_orientations),
1812
+ name);
1813
+}
1814
+EXPORT_SYMBOL_GPL(typec_find_orientation);
14041815
14051816 /**
14061817 * typec_find_port_power_role - Get the typec port power capability
....@@ -1461,13 +1872,13 @@
14611872 {
14621873 int ret;
14631874
1464
- if (port->sw) {
1465
- ret = port->sw->set(port->sw, orientation);
1466
- if (ret)
1467
- return ret;
1468
- }
1875
+ ret = typec_switch_set(port->sw, orientation);
1876
+ if (ret)
1877
+ return ret;
14691878
14701879 port->orientation = orientation;
1880
+ sysfs_notify(&port->dev.kobj, NULL, "orientation");
1881
+ kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
14711882
14721883 return 0;
14731884 }
....@@ -1495,11 +1906,52 @@
14951906 */
14961907 int typec_set_mode(struct typec_port *port, int mode)
14971908 {
1498
- return port->mux ? port->mux->set(port->mux, mode) : 0;
1909
+ struct typec_mux_state state = { };
1910
+
1911
+ state.mode = mode;
1912
+
1913
+ return typec_mux_set(port->mux, &state);
14991914 }
15001915 EXPORT_SYMBOL_GPL(typec_set_mode);
15011916
15021917 /* --------------------------------------- */
1918
+
1919
+/**
1920
+ * typec_get_negotiated_svdm_version - Get negotiated SVDM Version
1921
+ * @port: USB Type-C Port.
1922
+ *
1923
+ * Get the negotiated SVDM Version. The Version is set to the port default
1924
+ * value stored in typec_capability on partner registration, and updated after
1925
+ * a successful Discover Identity if the negotiated value is less than the
1926
+ * default value.
1927
+ *
1928
+ * Returns usb_pd_svdm_ver if the partner has been registered otherwise -ENODEV.
1929
+ */
1930
+int typec_get_negotiated_svdm_version(struct typec_port *port)
1931
+{
1932
+ enum usb_pd_svdm_ver svdm_version;
1933
+ struct device *partner_dev;
1934
+
1935
+ partner_dev = device_find_child(&port->dev, NULL, partner_match);
1936
+ if (!partner_dev)
1937
+ return -ENODEV;
1938
+
1939
+ svdm_version = to_typec_partner(partner_dev)->svdm_version;
1940
+ put_device(partner_dev);
1941
+
1942
+ return svdm_version;
1943
+}
1944
+EXPORT_SYMBOL_GPL(typec_get_negotiated_svdm_version);
1945
+
1946
+/**
1947
+ * typec_get_drvdata - Return private driver data pointer
1948
+ * @port: USB Type-C port
1949
+ */
1950
+void *typec_get_drvdata(struct typec_port *port)
1951
+{
1952
+ return dev_get_drvdata(&port->dev);
1953
+}
1954
+EXPORT_SYMBOL_GPL(typec_get_drvdata);
15031955
15041956 /**
15051957 * typec_port_register_altmode - Register USB Type-C Port Alternate Mode
....@@ -1551,20 +2003,20 @@
15512003 ret = fwnode_property_read_u32(child, "svid", &svid);
15522004 if (ret) {
15532005 dev_err(&port->dev, "Error reading svid for altmode %s\n",
1554
- kbasename(of_node_full_name(to_of_node(child))));
2006
+ fwnode_get_name(child));
15552007 continue;
15562008 }
15572009
15582010 ret = fwnode_property_read_u32(child, "vdo", &vdo);
15592011 if (ret) {
15602012 dev_err(&port->dev, "Error reading vdo for altmode %s\n",
1561
- kbasename(of_node_full_name(to_of_node(child))));
2013
+ fwnode_get_name(child));
15622014 continue;
15632015 }
15642016
15652017 if (index >= n) {
15662018 dev_err(&port->dev, "Error not enough space for altmode %s\n",
1567
- kbasename(of_node_full_name(to_of_node(child))));
2019
+ fwnode_get_name(child));
15682020 continue;
15692021 }
15702022
....@@ -1574,7 +2026,7 @@
15742026 alt = typec_port_register_altmode(port, &desc);
15752027 if (IS_ERR(alt)) {
15762028 dev_err(&port->dev, "Error registering altmode %s\n",
1577
- kbasename(of_node_full_name(to_of_node(child))));
2029
+ fwnode_get_name(child));
15782030 continue;
15792031 }
15802032
....@@ -1648,7 +2100,7 @@
16482100 mutex_init(&port->port_type_lock);
16492101
16502102 port->id = id;
1651
- port->cap = cap;
2103
+ port->ops = cap->ops;
16522104 port->port_type = cap->type;
16532105 port->prefer_role = cap->prefer_role;
16542106
....@@ -1658,6 +2110,13 @@
16582110 port->dev.fwnode = cap->fwnode;
16592111 port->dev.type = &typec_port_dev_type;
16602112 dev_set_name(&port->dev, "port%d", id);
2113
+ dev_set_drvdata(&port->dev, cap->driver_data);
2114
+
2115
+ port->cap = kmemdup(cap, sizeof(*cap), GFP_KERNEL);
2116
+ if (!port->cap) {
2117
+ put_device(&port->dev);
2118
+ return ERR_PTR(-ENOMEM);
2119
+ }
16612120
16622121 port->sw = typec_switch_get(&port->dev);
16632122 if (IS_ERR(port->sw)) {