1 From c223fa5f3cded17156fb781c1861a92349c4c5be Mon Sep 17 00:00:00 2001
2 From: Tobias Schramm <t.schramm@manjaro.org>
3 Date: Thu, 28 May 2020 14:01:59 +0200
4 Subject: [PATCH] leds: Add support for inverted LED triggers
6 Needs to be changed for upstream, invert via sysfs not trigger duplication
8 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
10 drivers/leds/led-core.c | 1 +
11 drivers/leds/led-triggers.c | 149 +++++++++++++++++++++++++++---------
12 include/linux/leds.h | 1 +
13 3 files changed, 113 insertions(+), 38 deletions(-)
15 diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
16 index c4e780bdb385..3973676d6f1e 100644
17 --- a/drivers/leds/led-core.c
18 +++ b/drivers/leds/led-core.c
19 @@ -177,6 +177,7 @@ static void led_blink_setup(struct led_classdev *led_cdev,
20 unsigned long *delay_off)
22 if (!test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags) &&
23 + !test_bit(LED_BLINK_INVERT, &led_cdev->work_flags) &&
24 led_cdev->blink_set &&
25 !led_cdev->blink_set(led_cdev, delay_on, delay_off))
27 diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
28 index 91da90cfb11d..7f2898a0e1e3 100644
29 --- a/drivers/leds/led-triggers.c
30 +++ b/drivers/leds/led-triggers.c
31 @@ -27,20 +27,89 @@ LIST_HEAD(trigger_list);
33 /* Used by LED Class */
37 trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig)
39 return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type;
43 +#define TRIGGER_INVERT_SUFFIX "-inverted"
46 + * Check suffix of trigger name agains TRIGGER_INVERT_SUFFIX
48 +static bool led_trigger_is_inverted(const char *trigname)
50 + if (strlen(trigname) >= strlen(TRIGGER_INVERT_SUFFIX)) {
51 + return !strcmp(trigname + strlen(trigname) -
52 + strlen(TRIGGER_INVERT_SUFFIX),
53 + TRIGGER_INVERT_SUFFIX);
60 + * Get length of trigger name name without TRIGGER_INVERT_SUFFIX
62 +static size_t led_trigger_get_name_len(const char *trigname)
64 + // Subtract length of TRIGGER_INVERT_SUFFIX if trigger is inverted
65 + if (led_trigger_is_inverted(trigname))
66 + return strlen(trigname) - strlen(TRIGGER_INVERT_SUFFIX);
67 + return strlen(trigname);
71 + * Find and set led trigger by name
73 +static int led_trigger_set_str_(struct led_classdev *led_cdev,
74 + const char *trigname, bool lock)
76 + struct led_trigger *trig;
77 + bool inverted = led_trigger_is_inverted(trigname);
78 + size_t len = led_trigger_get_name_len(trigname);
80 + down_read(&triggers_list_lock);
81 + list_for_each_entry(trig, &trigger_list, next_trig) {
82 + /* Compare trigger name without inversion suffix */
83 + if (strlen(trig->name) == len &&
84 + !strncmp(trigname, trig->name, len) &&
85 + trigger_relevant(led_cdev, trig)) {
87 + down_write(&led_cdev->trigger_lock);
88 + led_trigger_set(led_cdev, trig);
90 + led_cdev->flags |= LED_INVERT_TRIGGER;
92 + led_cdev->flags &= ~LED_INVERT_TRIGGER;
94 + up_write(&led_cdev->trigger_lock);
96 + up_read(&triggers_list_lock);
100 + /* we come here only if trigname matches no trigger */
101 + up_read(&triggers_list_lock);
105 +#define led_trigger_set_str(cdev, name) led_trigger_set_str_(cdev, name, true)
106 +#define led_trigger_set_str_unlocked(cdev, name) \
107 + led_trigger_set_str_(cdev, name, false)
110 ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
111 struct bin_attribute *bin_attr, char *buf,
112 loff_t pos, size_t count)
114 struct device *dev = kobj_to_dev(kobj);
115 struct led_classdev *led_cdev = dev_get_drvdata(dev);
116 - struct led_trigger *trig;
120 mutex_lock(&led_cdev->led_access);
122 @@ -54,20 +123,10 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
126 - down_read(&triggers_list_lock);
127 - list_for_each_entry(trig, &trigger_list, next_trig) {
128 - if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) {
129 - down_write(&led_cdev->trigger_lock);
130 - led_trigger_set(led_cdev, trig);
131 - up_write(&led_cdev->trigger_lock);
133 - up_read(&triggers_list_lock);
137 - /* we come here only if buf matches no trigger */
139 - up_read(&triggers_list_lock);
141 + ret = led_trigger_set_str(led_cdev, name);
146 mutex_unlock(&led_cdev->led_access);
147 @@ -99,16 +158,25 @@ static int led_trigger_format(char *buf, size_t size,
148 led_cdev->trigger ? "none" : "[none]");
150 list_for_each_entry(trig, &trigger_list, next_trig) {
152 + bool hit = led_cdev->trigger == trig;
153 + bool inverted = led_cdev->flags & LED_INVERT_TRIGGER;
155 if (!trigger_relevant(led_cdev, trig))
158 - hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name);
159 + /* print non-inverted trigger */
160 + len += led_trigger_snprintf(buf + len, size - len,
162 + hit && !inverted ? "[" : "",
164 + hit && !inverted ? "]" : "");
166 + /* print inverted trigger */
167 len += led_trigger_snprintf(buf + len, size - len,
168 - " %s%s%s", hit ? "[" : "",
169 - trig->name, hit ? "]" : "");
170 + " %s%s"TRIGGER_INVERT_SUFFIX"%s",
171 + hit && inverted ? "[" : "",
173 + hit && inverted ? "]" : "");
176 len += led_trigger_snprintf(buf + len, size - len, "\n");
177 @@ -245,22 +313,15 @@ EXPORT_SYMBOL_GPL(led_trigger_remove);
179 void led_trigger_set_default(struct led_classdev *led_cdev)
181 - struct led_trigger *trig;
184 if (!led_cdev->default_trigger)
187 down_read(&triggers_list_lock);
188 - down_write(&led_cdev->trigger_lock);
189 - list_for_each_entry(trig, &trigger_list, next_trig) {
190 - if (!strcmp(led_cdev->default_trigger, trig->name) &&
191 - trigger_relevant(led_cdev, trig)) {
192 - led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
193 - led_trigger_set(led_cdev, trig);
197 - up_write(&led_cdev->trigger_lock);
198 + found = !led_trigger_set_str(led_cdev, led_cdev->default_trigger);
200 + led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
201 up_read(&triggers_list_lock);
203 EXPORT_SYMBOL_GPL(led_trigger_set_default);
204 @@ -305,12 +366,15 @@ int led_trigger_register(struct led_trigger *trig)
205 /* Register with any LEDs that have this as a default trigger */
206 down_read(&leds_list_lock);
207 list_for_each_entry(led_cdev, &leds_list, node) {
210 down_write(&led_cdev->trigger_lock);
211 if (!led_cdev->trigger && led_cdev->default_trigger &&
212 - !strcmp(led_cdev->default_trigger, trig->name) &&
213 trigger_relevant(led_cdev, trig)) {
214 - led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
215 - led_trigger_set(led_cdev, trig);
216 + found = !led_trigger_set_str_unlocked(led_cdev,
217 + led_cdev->default_trigger);
219 + led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
221 up_write(&led_cdev->trigger_lock);
223 @@ -383,8 +447,14 @@ void led_trigger_event(struct led_trigger *trig,
226 read_lock_irqsave(&trig->leddev_list_lock, flags);
227 - list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
228 - led_set_brightness(led_cdev, brightness);
229 + list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
230 + /* Reverse brightness if LED is inverted */
231 + if (led_cdev->flags & LED_INVERT_TRIGGER)
232 + led_set_brightness(led_cdev,
233 + led_cdev->max_brightness - brightness);
235 + led_set_brightness(led_cdev, brightness);
237 read_unlock_irqrestore(&trig->leddev_list_lock, flags);
239 EXPORT_SYMBOL_GPL(led_trigger_event);
240 @@ -402,10 +472,13 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
242 read_lock_irqsave(&trig->leddev_list_lock, flags);
243 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
245 + bool trigger_inverted =
246 + !!(led_cdev->flags & LED_INVERT_TRIGGER);
248 + /* use logical xnor to determine inversion parameter */
249 led_blink_set_oneshot(led_cdev, delay_on, delay_off,
252 + (!!invert) == trigger_inverted);
254 led_blink_set(led_cdev, delay_on, delay_off);
256 read_unlock_irqrestore(&trig->leddev_list_lock, flags);
257 diff --git a/include/linux/leds.h b/include/linux/leds.h
258 index 6a8d6409c993..9cbf42cf08e8 100644
259 --- a/include/linux/leds.h
260 +++ b/include/linux/leds.h
261 @@ -79,6 +79,7 @@ struct led_classdev {
262 #define LED_BRIGHT_HW_CHANGED BIT(21)
263 #define LED_RETAIN_AT_SHUTDOWN BIT(22)
264 #define LED_INIT_DEFAULT_TRIGGER BIT(23)
265 +#define LED_INVERT_TRIGGER BIT(24)
267 /* set_brightness_work / blink_timer flags, atomic, private. */
268 unsigned long work_flags;
272 From 90a117ec260f54078aabcf2c1cde72f4425116ba Mon Sep 17 00:00:00 2001
273 From: Tobias Schramm <t.schramm@manjaro.org>
274 Date: Thu, 28 May 2020 14:12:56 +0200
275 Subject: [PATCH] tty: serdev: support shutdown op
277 Allow serdev drivers to register a shutdown handler
279 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
281 drivers/tty/serdev/core.c | 11 +++++++++++
282 include/linux/serdev.h | 1 +
283 2 files changed, 12 insertions(+)
285 diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
286 index c5f0d936b003..37e45c356540 100644
287 --- a/drivers/tty/serdev/core.c
288 +++ b/drivers/tty/serdev/core.c
289 @@ -432,11 +432,22 @@ static int serdev_drv_remove(struct device *dev)
290 dev_pm_domain_detach(dev, true);
293 +static void serdev_drv_shutdown(struct device *dev)
295 + const struct serdev_device_driver *sdrv;
297 + sdrv = to_serdev_device_driver(dev->driver);
298 + if (sdrv->shutdown)
299 + sdrv->shutdown(to_serdev_device(dev));
303 static struct bus_type serdev_bus_type = {
305 .match = serdev_device_match,
306 .probe = serdev_drv_probe,
307 .remove = serdev_drv_remove,
308 + .shutdown = serdev_drv_shutdown,
312 diff --git a/include/linux/serdev.h b/include/linux/serdev.h
313 index 9f14f9c12ec4..94050561325c 100644
314 --- a/include/linux/serdev.h
315 +++ b/include/linux/serdev.h
316 @@ -63,6 +63,7 @@ struct serdev_device_driver {
317 struct device_driver driver;
318 int (*probe)(struct serdev_device *);
319 void (*remove)(struct serdev_device *);
320 + void (*shutdown)(struct serdev_device *);
323 static inline struct serdev_device_driver *to_serdev_device_driver(struct device_driver *d)
327 From 4381cb3400bd61288d2122f3eb74711963885323 Mon Sep 17 00:00:00 2001
328 From: Tobias Schramm <t.schramm@manjaro.org>
329 Date: Thu, 28 May 2020 14:14:06 +0200
330 Subject: [PATCH] bluetooth: hci_serdev: Clear registered bit on unregister
332 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
334 drivers/bluetooth/hci_serdev.c | 2 ++
335 1 file changed, 2 insertions(+)
337 diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
338 index ef96ad06fa54..95c723c0ea01 100644
339 --- a/drivers/bluetooth/hci_serdev.c
340 +++ b/drivers/bluetooth/hci_serdev.c
341 @@ -395,5 +395,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
342 clear_bit(HCI_UART_PROTO_READY, &hu->flags);
343 serdev_device_close(hu->serdev);
346 + clear_bit(HCI_UART_REGISTERED, &hu->flags);
348 EXPORT_SYMBOL_GPL(hci_uart_unregister_device);
352 From 4065c5018d7d4fc7d6ea51056a954f23320688ca Mon Sep 17 00:00:00 2001
353 From: Tobias Schramm <t.schramm@manjaro.org>
354 Date: Thu, 28 May 2020 14:15:08 +0200
355 Subject: [PATCH] bluetooth: hci_bcm: disable power on shutdown
357 Firmware behaves wonky when not power cycled over reboots
359 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
361 drivers/bluetooth/hci_bcm.c | 18 ++++++++++++++++++
362 1 file changed, 18 insertions(+)
364 diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
365 index 8ea5ca8d71d6..6d5871992f79 100644
366 --- a/drivers/bluetooth/hci_bcm.c
367 +++ b/drivers/bluetooth/hci_bcm.c
368 @@ -1469,6 +1469,23 @@ static void bcm_serdev_remove(struct serdev_device *serdev)
369 hci_uart_unregister_device(&bcmdev->serdev_hu);
372 +static void bcm_serdev_shutdown(struct serdev_device *serdev)
374 + struct bcm_device *bcmdev = serdev_device_get_drvdata(serdev);
377 + if (test_bit(HCI_UART_REGISTERED, &bcmdev->hu->flags)) {
378 + hci_uart_unregister_device(&bcmdev->serdev_hu);
381 + dev_info(bcmdev->dev, "Cutting power to bluetooth module\n");
382 + if (bcm_gpio_set_power(bcmdev, false)) {
383 + dev_err(bcmdev->dev, "Failed to power down\n");
385 + usleep_range(500000, 1000000);
390 static struct bcm_device_data bcm4354_device_data = {
391 .no_early_set_baudrate = true,
392 @@ -1494,6 +1511,7 @@ MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match);
393 static struct serdev_device_driver bcm_serdev_driver = {
394 .probe = bcm_serdev_probe,
395 .remove = bcm_serdev_remove,
396 + .shutdown = bcm_serdev_shutdown,
398 .name = "hci_uart_bcm",
399 .of_match_table = of_match_ptr(bcm_bluetooth_of_match),
403 From f6419edc62979c1e67202b5dc10abd7b22bdedcf Mon Sep 17 00:00:00 2001
404 From: Tobias Schramm <t.schramm@manjaro.org>
405 Date: Thu, 28 May 2020 14:16:52 +0200
406 Subject: [PATCH] mmc: core: pwrseq_simple: disable mmc power on shutdown
408 Fix for Broadcom SDIO WiFi modules. They misbehave if reinitialized
409 without a power cycle.
411 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
413 drivers/mmc/core/pwrseq_simple.c | 19 ++++++++++++++++---
414 1 file changed, 16 insertions(+), 3 deletions(-)
416 diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
417 index ea4d3670560e..38fe7e29aba6 100644
418 --- a/drivers/mmc/core/pwrseq_simple.c
419 +++ b/drivers/mmc/core/pwrseq_simple.c
420 @@ -80,10 +80,8 @@ static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
421 msleep(pwrseq->post_power_on_delay_ms);
424 -static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
425 +static void __mmc_pwrseq_simple_power_off(struct mmc_pwrseq_simple *pwrseq)
427 - struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
429 mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
431 if (pwrseq->power_off_delay_us)
432 @@ -96,6 +94,12 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
436 +static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
438 + struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
439 + __mmc_pwrseq_simple_power_off(pwrseq);
442 static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
443 .pre_power_on = mmc_pwrseq_simple_pre_power_on,
444 .post_power_on = mmc_pwrseq_simple_post_power_on,
445 @@ -151,9 +155,18 @@ static int mmc_pwrseq_simple_remove(struct platform_device *pdev)
449 +static void mmc_pwrseq_simple_shutdown(struct platform_device *pdev)
451 + struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev);
453 + dev_info(&pdev->dev, "Turning off mmc\n");
454 + __mmc_pwrseq_simple_power_off(pwrseq);
457 static struct platform_driver mmc_pwrseq_simple_driver = {
458 .probe = mmc_pwrseq_simple_probe,
459 .remove = mmc_pwrseq_simple_remove,
460 + .shutdown = mmc_pwrseq_simple_shutdown,
462 .name = "pwrseq_simple",
463 .of_match_table = mmc_pwrseq_simple_of_match,
467 From b0452434e75ecf257bc2ea9a5eb86be68bb56f71 Mon Sep 17 00:00:00 2001
468 From: Tobias Schramm <t.schramm@manjaro.org>
469 Date: Thu, 28 May 2020 14:23:54 +0200
470 Subject: [PATCH] usb: typec: tcpm: add hacky generic altmode support
472 This is a hack and it is based on extcon. Do not try to mainline
473 unless you are in need for some retroactive abortion by the
476 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
478 drivers/usb/typec/tcpm/tcpm.c | 139 +++++++++++++++++++++++++++++++++-
479 1 file changed, 138 insertions(+), 1 deletion(-)
481 diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
482 index a6fae1f86505..2908771f4d4e 100644
483 --- a/drivers/usb/typec/tcpm/tcpm.c
484 +++ b/drivers/usb/typec/tcpm/tcpm.c
486 #include <linux/debugfs.h>
487 #include <linux/device.h>
488 #include <linux/hrtimer.h>
489 +#include <linux/extcon-provider.h>
490 #include <linux/jiffies.h>
491 #include <linux/kernel.h>
492 #include <linux/kthread.h>
493 @@ -369,6 +370,11 @@ struct tcpm_port {
494 * SNK_READY for non-pd link.
496 bool slow_charger_loop;
497 +#ifdef CONFIG_EXTCON
498 + struct extcon_dev *extcon;
499 + unsigned int *extcon_cables;
502 #ifdef CONFIG_DEBUG_FS
503 struct dentry *dentry;
504 struct mutex logbuffer_lock; /* log buffer access lock */
505 @@ -654,6 +660,35 @@ static void tcpm_debugfs_exit(const struct tcpm_port *port) { }
509 +static void tcpm_update_extcon_data(struct tcpm_port *port, bool attached) {
510 +#ifdef CONFIG_EXTCON
511 + unsigned int *capability = port->extcon_cables;
512 + if (port->data_role == TYPEC_HOST) {
513 + extcon_set_state(port->extcon, EXTCON_USB, false);
514 + extcon_set_state(port->extcon, EXTCON_USB_HOST, attached);
516 + extcon_set_state(port->extcon, EXTCON_USB, true);
517 + extcon_set_state(port->extcon, EXTCON_USB_HOST, attached);
519 + while (*capability != EXTCON_NONE) {
521 + union extcon_property_value val;
522 + val.intval = (port->polarity == TYPEC_POLARITY_CC2);
523 + extcon_set_property(port->extcon, *capability,
524 + EXTCON_PROP_USB_TYPEC_POLARITY, val);
526 + extcon_set_state(port->extcon, *capability, false);
528 + extcon_sync(port->extcon, *capability);
531 + tcpm_log(port, "Extcon update (%s): %s, %s",
532 + attached ? "attached" : "detached",
533 + port->data_role == TYPEC_HOST ? "host" : "device",
534 + port->polarity == TYPEC_POLARITY_CC1 ? "normal" : "flipped");
538 static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
540 tcpm_log(port, "cc:=%d", cc);
541 @@ -881,6 +916,8 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
542 typec_set_data_role(port->typec_port, data);
543 typec_set_pwr_role(port->typec_port, role);
545 + tcpm_update_extcon_data(port, attached);
550 @@ -1132,7 +1169,7 @@ static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt)
552 paltmode->vdo = p[i];
554 - tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x",
555 + tcpm_log(port, "Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x",
556 pmdata->altmodes, paltmode->svid,
557 paltmode->mode, paltmode->vdo);
559 @@ -1154,6 +1191,9 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
560 modep->altmode_desc[i].svid);
564 + tcpm_log(port, "Registered altmode 0x%04x", modep->altmode_desc[i].svid);
566 port->partner_altmode[i] = altmode;
569 @@ -1249,9 +1289,11 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
571 if (modep->svid_index < modep->nsvids) {
572 u16 svid = modep->svids[modep->svid_index];
573 + tcpm_log(port, "More modes available, sending discover");
574 response[0] = VDO(svid, 1, svdm_version, CMD_DISCOVER_MODES);
577 + tcpm_log(port, "Got all patner modes, registering");
578 tcpm_register_partner_altmodes(port);
581 @@ -2836,6 +2878,7 @@ static int tcpm_src_attach(struct tcpm_port *port)
582 static void tcpm_typec_disconnect(struct tcpm_port *port)
584 if (port->connected) {
585 + tcpm_update_extcon_data(port, false);
586 typec_unregister_partner(port->partner);
587 port->partner = NULL;
588 port->connected = false;
589 @@ -2902,6 +2945,8 @@ static void tcpm_detach(struct tcpm_port *port)
592 tcpm_reset_port(port);
594 + tcpm_update_extcon_data(port, false);
597 static void tcpm_src_detach(struct tcpm_port *port)
598 @@ -4732,6 +4777,64 @@ void tcpm_tcpc_reset(struct tcpm_port *port)
600 EXPORT_SYMBOL_GPL(tcpm_tcpc_reset);
602 +unsigned int default_supported_cables[] = {
606 +static int tcpm_fw_get_caps_late(struct tcpm_port *port,
607 + struct fwnode_handle *fwnode)
610 + ret = fwnode_property_count_u32(fwnode, "typec-altmodes");
614 + dev_err(port->dev, "Length of typec altmode array must be divisible by 4");
618 + props = devm_kzalloc(port->dev, sizeof(u32) * ret, GFP_KERNEL);
620 + dev_err(port->dev, "Failed to allocate memory for altmode properties");
624 + if(fwnode_property_read_u32_array(fwnode, "typec-altmodes", props, ret) < 0) {
625 + dev_err(port->dev, "Failed to read altmodes from port");
630 + while (ret > 0 && i < ARRAY_SIZE(port->port_altmode)) {
631 + struct typec_altmode *alt;
632 + struct typec_altmode_desc alt_desc = {
633 + .svid = props[i * 4],
634 + .mode = props[i * 4 + 1],
635 + .vdo = props[i * 4 + 2],
636 + .roles = props[i * 4 + 3],
640 + tcpm_log(port, "Adding altmode SVID: 0x%04x, mode: %d, vdo: %u, role: %d",
641 + alt_desc.svid, alt_desc.mode, alt_desc.vdo, alt_desc.roles);
642 + alt = typec_port_register_altmode(port->typec_port,
646 + "%s: failed to register port alternate mode 0x%x",
647 + dev_name(port->dev), alt_desc.svid);
650 + typec_altmode_set_drvdata(alt, port);
651 + alt->ops = &tcpm_altmode_ops;
652 + port->port_altmode[i] = alt;
660 static int tcpm_fw_get_caps(struct tcpm_port *port,
661 struct fwnode_handle *fwnode)
663 @@ -4742,6 +4845,23 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
665 fw_devlink_purge_absent_suppliers(fwnode);
667 +#ifdef CONFIG_EXTCON
668 + ret = fwnode_property_count_u32(fwnode, "extcon-cables");
670 + port->extcon_cables = devm_kzalloc(port->dev, sizeof(u32) * ret, GFP_KERNEL);
671 + if (!port->extcon_cables) {
672 + dev_err(port->dev, "Failed to allocate memory for extcon cable types. "\
673 + "Using default tyes");
674 + goto extcon_default;
676 + fwnode_property_read_u32_array(fwnode, "extcon-cables", port->extcon_cables, ret);
679 + dev_info(port->dev, "No cable types defined, using default cables");
680 + port->extcon_cables = default_supported_cables;
684 /* USB data support is optional */
685 ret = fwnode_property_read_string(fwnode, "data-role", &cap_str);
687 @@ -5114,6 +5234,17 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
690 port->try_role = port->typec_caps.prefer_role;
691 +#ifdef CONFIG_EXTCON
692 + port->extcon = devm_extcon_dev_allocate(dev, port->extcon_cables);
693 + if (IS_ERR(port->extcon)) {
694 + dev_err(dev, "Failed to allocate extcon device: %ld", PTR_ERR(port->extcon));
695 + goto out_destroy_wq;
697 + if((err = devm_extcon_dev_register(dev, port->extcon))) {
698 + dev_err(dev, "Failed to register extcon device: %d", err);
699 + goto out_destroy_wq;
703 port->typec_caps.fwnode = tcpc->fwnode;
704 port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
705 @@ -5141,6 +5272,12 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
706 &tcpm_altmode_ops, port,
707 port->port_altmode, ALTMODE_DISCOVERY_MAX);
709 + err = tcpm_fw_get_caps_late(port, tcpc->fwnode);
711 + dev_err(dev, "Failed to get altmodes from fwnode");
712 + goto out_destroy_wq;
715 mutex_lock(&port->lock);
717 mutex_unlock(&port->lock);
721 From db4e9ffdb985752ae3c3436ff86f8f376ae8fd22 Mon Sep 17 00:00:00 2001
722 From: Tobias Schramm <t.schramm@manjaro.org>
723 Date: Thu, 28 May 2020 14:25:32 +0200
724 Subject: [PATCH] phy: rockchip: typec: Set extcon capabilities
726 Do not mainline, hack.
728 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
730 drivers/phy/rockchip/phy-rockchip-typec.c | 17 +++++++++++++++++
731 1 file changed, 17 insertions(+)
733 diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
734 index 70a31251b202..5385bb4f0bd4 100644
735 --- a/drivers/phy/rockchip/phy-rockchip-typec.c
736 +++ b/drivers/phy/rockchip/phy-rockchip-typec.c
738 #include <linux/clk-provider.h>
739 #include <linux/delay.h>
740 #include <linux/extcon.h>
741 +#include <linux/extcon-provider.h>
742 #include <linux/io.h>
743 #include <linux/iopoll.h>
744 #include <linux/kernel.h>
745 @@ -1160,6 +1161,22 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
746 dev_err(dev, "Invalid or missing extcon\n");
747 return PTR_ERR(tcphy->extcon);
750 + extcon_set_property_capability(tcphy->extcon, EXTCON_USB,
751 + EXTCON_PROP_USB_SS);
752 + extcon_set_property_capability(tcphy->extcon, EXTCON_USB_HOST,
753 + EXTCON_PROP_USB_SS);
754 + extcon_set_property_capability(tcphy->extcon, EXTCON_DISP_DP,
755 + EXTCON_PROP_USB_SS);
756 + extcon_set_property_capability(tcphy->extcon, EXTCON_USB,
757 + EXTCON_PROP_USB_TYPEC_POLARITY);
758 + extcon_set_property_capability(tcphy->extcon, EXTCON_USB_HOST,
759 + EXTCON_PROP_USB_TYPEC_POLARITY);
760 + extcon_set_property_capability(tcphy->extcon, EXTCON_DISP_DP,
761 + EXTCON_PROP_USB_TYPEC_POLARITY);
762 + extcon_sync(tcphy->extcon, EXTCON_USB);
763 + extcon_sync(tcphy->extcon, EXTCON_USB_HOST);
764 + extcon_sync(tcphy->extcon, EXTCON_DISP_DP);
767 pm_runtime_enable(dev);
771 From fd739ae47f9ea780a1e161a478e241df06eaff7e Mon Sep 17 00:00:00 2001
772 From: Tobias Schramm <t.schramm@manjaro.org>
773 Date: Thu, 28 May 2020 14:26:27 +0200
774 Subject: [PATCH] usb: typec: altmodes: displayport: Add hacky, generic altmode
777 Do not mainline, hack.
779 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
781 drivers/usb/typec/altmodes/displayport.c | 55 ++++++++++++++++++++++--
782 1 file changed, 52 insertions(+), 3 deletions(-)
784 diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
785 index e62e5e3da01e..a3d03db476aa 100644
786 --- a/drivers/usb/typec/altmodes/displayport.c
787 +++ b/drivers/usb/typec/altmodes/displayport.c
791 #include <linux/delay.h>
792 +#include <linux/extcon.h>
793 +#include <linux/extcon-provider.h>
794 #include <linux/mutex.h>
795 #include <linux/module.h>
796 #include <linux/usb/pd_vdo.h>
797 @@ -135,15 +137,53 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
801 +static void dp_altmode_update_extcon(struct dp_altmode *dp, bool disconnect) {
802 + const struct device *dev = &dp->port->dev;
803 + struct extcon_dev* edev = NULL;
806 + edev = extcon_find_edev_by_node(dev->of_node);
807 + if(!IS_ERR(edev)) {
813 + if (IS_ERR_OR_NULL(edev)) {
817 + if (disconnect || !dp->data.conf) {
818 + extcon_set_state_sync(edev, EXTCON_DISP_DP, false);
820 + union extcon_property_value extcon_true = { .intval = true };
821 + extcon_set_state(edev, EXTCON_DISP_DP, true);
822 + if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf) & DP_PIN_ASSIGN_MULTI_FUNC_MASK) {
823 + extcon_set_state_sync(edev, EXTCON_USB_HOST, true);
824 + extcon_set_property(edev, EXTCON_DISP_DP, EXTCON_PROP_USB_SS,
827 + extcon_set_state_sync(edev, EXTCON_USB_HOST, false);
829 + extcon_sync(edev, EXTCON_DISP_DP);
830 + extcon_set_state_sync(edev, EXTCON_USB, false);
835 static int dp_altmode_configured(struct dp_altmode *dp)
839 sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
841 - if (!dp->data.conf)
842 + if (!dp->data.conf) {
843 + dp_altmode_update_extcon(dp, true);
844 return typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
848 + dp_altmode_update_extcon(dp, false);
850 ret = dp_altmode_notify(dp);
852 @@ -170,9 +210,11 @@ static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
854 if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf))
855 dp_altmode_notify(dp);
858 + dp_altmode_update_extcon(dp, true);
859 typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
865 @@ -211,6 +253,8 @@ static void dp_altmode_work(struct work_struct *work)
867 if (typec_altmode_exit(dp->alt))
868 dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
870 + dp_altmode_update_extcon(dp, true);
874 @@ -521,8 +565,13 @@ int dp_altmode_probe(struct typec_altmode *alt)
875 if (!(DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) &
876 DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo)) &&
877 !(DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) &
878 - DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo)))
879 + DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo))) {
880 + dev_err(&alt->dev, "No compatible pin configuration found:"\
881 + "%04lx -> %04lx, %04lx <- %04lx",
882 + DP_CAP_DFP_D_PIN_ASSIGN(port->vdo), DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo),
883 + DP_CAP_UFP_D_PIN_ASSIGN(port->vdo), DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo));
887 ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group);
892 From e9d07cf5d983a3b941e604ae4ba9d277929e0650 Mon Sep 17 00:00:00 2001
893 From: Tobias Schramm <t.schramm@manjaro.org>
894 Date: Thu, 28 May 2020 14:34:47 +0200
895 Subject: [PATCH] sound: soc: codecs: es8316: Run micdetect only if jack status
898 Think this is (was?) required to prevent flapping of detection status on
901 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
903 sound/soc/codecs/es8316.c | 2 +-
904 1 file changed, 1 insertion(+), 1 deletion(-)
906 diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
907 index bd5d230c5df2..a2d8bf620b6f 100644
908 --- a/sound/soc/codecs/es8316.c
909 +++ b/sound/soc/codecs/es8316.c
910 @@ -688,7 +688,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
911 snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
912 ES8316_GPIO_ENABLE_INTERRUPT, 0);
914 - if (es8316->jack->status & SND_JACK_MICROPHONE) {
915 + if (es8316->jack && (es8316->jack->status & SND_JACK_MICROPHONE)) {
916 es8316_disable_micbias_for_mic_gnd_short_detect(component);
917 snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0);
922 From edbf5d93dbd845faa4aa74fb8a7c5e76cf35ef0d Mon Sep 17 00:00:00 2001
923 From: Tobias Schramm <t.schramm@manjaro.org>
924 Date: Thu, 28 May 2020 14:36:47 +0200
925 Subject: [PATCH] ASoC: soc-jack.c: supported inverted jack detect GPIOs
927 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
929 sound/soc/soc-jack.c | 7 ++++---
930 1 file changed, 4 insertions(+), 3 deletions(-)
932 diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
933 index 0f1820f36b4d..8d9d77814f33 100644
934 --- a/sound/soc/soc-jack.c
935 +++ b/sound/soc/soc-jack.c
936 @@ -216,8 +216,6 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
939 enable = gpiod_get_value_cansleep(gpio->desc);
944 report = gpio->report;
945 @@ -346,6 +344,9 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
949 + int flags = GPIOF_IN;
950 + if (gpios[i].invert)
951 + flags |= GPIOF_ACTIVE_LOW;
952 /* legacy GPIO number */
953 if (!gpio_is_valid(gpios[i].gpio)) {
954 dev_err(jack->card->dev,
955 @@ -355,7 +356,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
959 - ret = gpio_request_one(gpios[i].gpio, GPIOF_IN,
960 + ret = gpio_request_one(gpios[i].gpio, flags,
967 From 948d7ade0ddcf292b91d91cb8b6819a19ab3f604 Mon Sep 17 00:00:00 2001
968 From: Tobias Schramm <t.schramm@manjaro.org>
969 Date: Thu, 28 May 2020 14:44:15 +0200
970 Subject: [PATCH] arm64: dts: rockchip: add typec extcon hack
974 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
976 arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts | 5 +++++
977 1 file changed, 5 insertions(+)
979 diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
980 index decb212e2dca..37f967a89401 100644
981 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
982 +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
983 @@ -401,6 +401,7 @@ opp08 {
991 @@ -735,6 +736,9 @@ connector {
992 <PDO_FIXED(5000, 1400, PDO_FIXED_USB_COMM)>;
993 try-power-role = "sink";
995 + extcon-cables = <1 2 5 6 9 10 12 44>;
996 + typec-altmodes = <0xff01 1 0x001c0000 1>;
999 #address-cells = <1>;
1001 @@ -1002,6 +1006,7 @@ spiflash: flash@0 {
1005 + extcon = <&fusb0>;
1012 From a8f3e4ffe533f952a468cb8f3d067865bd58144f Mon Sep 17 00:00:00 2001
1013 From: Tobias Schramm <t.schramm@manjaro.org>
1014 Date: Sat, 6 Jun 2020 23:45:10 +0200
1015 Subject: [PATCH] arm64: dts: rockchip: setup USB type c port as dual data role
1017 Some chargers try to put the charged device into device data role.
1018 Before this commit this condition caused the tcpm state machine to
1019 issue a hard reset due to a capability missmatch.
1021 Signed-off-by: Tobias Schramm <t.schramm@manjaro.org>
1023 arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts | 2 +-
1024 1 file changed, 1 insertion(+), 1 deletion(-)
1026 diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
1027 index c505c88b5d9b..d77dca5524ff 100644
1028 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
1029 +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
1030 @@ -726,7 +726,7 @@ fusb0: fusb30x@22 {
1033 compatible = "usb-c-connector";
1034 - data-role = "host";
1035 + data-role = "dual";
1037 op-sink-microwatt = <1000000>;
1038 power-role = "dual";