Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * USB Power Delivery sysfs entries
  4 *
  5 * Copyright (C) 2022, Intel Corporation
  6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
  7 */
  8
  9#include <linux/slab.h>
 10#include <linux/usb/pd.h>
 11
 12#include "pd.h"
 13
 14static DEFINE_IDA(pd_ida);
 15
 16static struct class pd_class = {
 17	.name = "usb_power_delivery",
 18	.owner = THIS_MODULE,
 19};
 20
 21#define to_pdo(o) container_of(o, struct pdo, dev)
 22
 23struct pdo {
 24	struct device dev;
 25	int object_position;
 26	u32 pdo;
 27};
 28
 29static void pdo_release(struct device *dev)
 30{
 31	kfree(to_pdo(dev));
 32}
 33
 34/* -------------------------------------------------------------------------- */
 35/* Fixed Supply */
 36
 37static ssize_t
 38dual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf)
 39{
 40	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE));
 41}
 42static DEVICE_ATTR_RO(dual_role_power);
 43
 44static ssize_t
 45usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf)
 46{
 47	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND));
 48}
 49static DEVICE_ATTR_RO(usb_suspend_supported);
 50
 51static ssize_t
 52unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf)
 53{
 54	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER));
 55}
 56static DEVICE_ATTR_RO(unconstrained_power);
 57
 58static ssize_t
 59usb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf)
 60{
 61	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM));
 62}
 63static DEVICE_ATTR_RO(usb_communication_capable);
 64
 65static ssize_t
 66dual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf)
 67{
 68	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP));
 69}
 70static DEVICE_ATTR_RO(dual_role_data);
 71
 72static ssize_t
 73unchunked_extended_messages_supported_show(struct device *dev,
 74					   struct device_attribute *attr, char *buf)
 75{
 76	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT));
 77}
 78static DEVICE_ATTR_RO(unchunked_extended_messages_supported);
 79
 80/*
 81 * REVISIT: Peak Current requires access also to the RDO.
 82static ssize_t
 83peak_current_show(struct device *dev, struct device_attribute *attr, char *buf)
 84{
 85	...
 86}
 87*/
 88
 89static ssize_t
 90fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf)
 91{
 92	return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3;
 93}
 94static DEVICE_ATTR_RO(fast_role_swap_current);
 95
 96static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
 97{
 98	return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo));
 99}
100static DEVICE_ATTR_RO(voltage);
101
102/* Shared with Variable supplies, both source and sink */
103static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf)
104{
105	return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo));
106}
107
108/* Shared with Variable type supplies */
109static struct device_attribute maximum_current_attr = {
110	.attr = {
111		.name = "maximum_current",
112		.mode = 0444,
113	},
114	.show = current_show,
115};
116
117static struct device_attribute operational_current_attr = {
118	.attr = {
119		.name = "operational_current",
120		.mode = 0444,
121	},
122	.show = current_show,
123};
124
125static struct attribute *source_fixed_supply_attrs[] = {
126	&dev_attr_dual_role_power.attr,
127	&dev_attr_usb_suspend_supported.attr,
128	&dev_attr_unconstrained_power.attr,
129	&dev_attr_usb_communication_capable.attr,
130	&dev_attr_dual_role_data.attr,
131	&dev_attr_unchunked_extended_messages_supported.attr,
132	/*&dev_attr_peak_current.attr,*/
133	&dev_attr_voltage.attr,
134	&maximum_current_attr.attr,
135	NULL
136};
137
138static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
139{
140	if (to_pdo(kobj_to_dev(kobj))->object_position &&
141	    /*attr != &dev_attr_peak_current.attr &&*/
142	    attr != &dev_attr_voltage.attr &&
143	    attr != &maximum_current_attr.attr &&
144	    attr != &operational_current_attr.attr)
145		return 0;
146
147	return attr->mode;
148}
149
150static const struct attribute_group source_fixed_supply_group = {
151	.is_visible = fixed_attr_is_visible,
152	.attrs = source_fixed_supply_attrs,
153};
154__ATTRIBUTE_GROUPS(source_fixed_supply);
155
156static struct device_type source_fixed_supply_type = {
157	.name = "pdo",
158	.release = pdo_release,
159	.groups = source_fixed_supply_groups,
160};
161
162static struct attribute *sink_fixed_supply_attrs[] = {
163	&dev_attr_dual_role_power.attr,
164	&dev_attr_usb_suspend_supported.attr,
165	&dev_attr_unconstrained_power.attr,
166	&dev_attr_usb_communication_capable.attr,
167	&dev_attr_dual_role_data.attr,
168	&dev_attr_unchunked_extended_messages_supported.attr,
169	&dev_attr_fast_role_swap_current.attr,
170	&dev_attr_voltage.attr,
171	&operational_current_attr.attr,
172	NULL
173};
174
175static const struct attribute_group sink_fixed_supply_group = {
176	.is_visible = fixed_attr_is_visible,
177	.attrs = sink_fixed_supply_attrs,
178};
179__ATTRIBUTE_GROUPS(sink_fixed_supply);
180
181static struct device_type sink_fixed_supply_type = {
182	.name = "pdo",
183	.release = pdo_release,
184	.groups = sink_fixed_supply_groups,
185};
186
187/* -------------------------------------------------------------------------- */
188/* Variable Supply */
189
190static ssize_t
191maximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
192{
193	return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo));
194}
195static DEVICE_ATTR_RO(maximum_voltage);
196
197static ssize_t
198minimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
199{
200	return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo));
201}
202static DEVICE_ATTR_RO(minimum_voltage);
203
204static struct attribute *source_variable_supply_attrs[] = {
205	&dev_attr_maximum_voltage.attr,
206	&dev_attr_minimum_voltage.attr,
207	&maximum_current_attr.attr,
208	NULL
209};
210ATTRIBUTE_GROUPS(source_variable_supply);
211
212static struct device_type source_variable_supply_type = {
213	.name = "pdo",
214	.release = pdo_release,
215	.groups = source_variable_supply_groups,
216};
217
218static struct attribute *sink_variable_supply_attrs[] = {
219	&dev_attr_maximum_voltage.attr,
220	&dev_attr_minimum_voltage.attr,
221	&operational_current_attr.attr,
222	NULL
223};
224ATTRIBUTE_GROUPS(sink_variable_supply);
225
226static struct device_type sink_variable_supply_type = {
227	.name = "pdo",
228	.release = pdo_release,
229	.groups = sink_variable_supply_groups,
230};
231
232/* -------------------------------------------------------------------------- */
233/* Battery */
234
235static ssize_t
236maximum_power_show(struct device *dev, struct device_attribute *attr, char *buf)
237{
238	return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo));
239}
240static DEVICE_ATTR_RO(maximum_power);
241
242static ssize_t
243operational_power_show(struct device *dev, struct device_attribute *attr, char *buf)
244{
245	return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo));
246}
247static DEVICE_ATTR_RO(operational_power);
248
249static struct attribute *source_battery_attrs[] = {
250	&dev_attr_maximum_voltage.attr,
251	&dev_attr_minimum_voltage.attr,
252	&dev_attr_maximum_power.attr,
253	NULL
254};
255ATTRIBUTE_GROUPS(source_battery);
256
257static struct device_type source_battery_type = {
258	.name = "pdo",
259	.release = pdo_release,
260	.groups = source_battery_groups,
261};
262
263static struct attribute *sink_battery_attrs[] = {
264	&dev_attr_maximum_voltage.attr,
265	&dev_attr_minimum_voltage.attr,
266	&dev_attr_operational_power.attr,
267	NULL
268};
269ATTRIBUTE_GROUPS(sink_battery);
270
271static struct device_type sink_battery_type = {
272	.name = "pdo",
273	.release = pdo_release,
274	.groups = sink_battery_groups,
275};
276
277/* -------------------------------------------------------------------------- */
278/* Standard Power Range (SPR) Programmable Power Supply (PPS) */
279
280static ssize_t
281pps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf)
282{
283	return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27)));
284}
285static DEVICE_ATTR_RO(pps_power_limited);
286
287static ssize_t
288pps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
289{
290	return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo));
291}
292
293static ssize_t
294pps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
295{
296	return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo));
297}
298
299static ssize_t
300pps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf)
301{
302	return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo));
303}
304
305static struct device_attribute pps_max_voltage_attr = {
306	.attr = {
307		.name = "maximum_voltage",
308		.mode = 0444,
309	},
310	.show = pps_max_voltage_show,
311};
312
313static struct device_attribute pps_min_voltage_attr = {
314	.attr = {
315		.name = "minimum_voltage",
316		.mode = 0444,
317	},
318	.show = pps_min_voltage_show,
319};
320
321static struct device_attribute pps_max_current_attr = {
322	.attr = {
323		.name = "maximum_current",
324		.mode = 0444,
325	},
326	.show = pps_max_current_show,
327};
328
329static struct attribute *source_pps_attrs[] = {
330	&dev_attr_pps_power_limited.attr,
331	&pps_max_voltage_attr.attr,
332	&pps_min_voltage_attr.attr,
333	&pps_max_current_attr.attr,
334	NULL
335};
336ATTRIBUTE_GROUPS(source_pps);
337
338static struct device_type source_pps_type = {
339	.name = "pdo",
340	.release = pdo_release,
341	.groups = source_pps_groups,
342};
343
344static struct attribute *sink_pps_attrs[] = {
345	&pps_max_voltage_attr.attr,
346	&pps_min_voltage_attr.attr,
347	&pps_max_current_attr.attr,
348	NULL
349};
350ATTRIBUTE_GROUPS(sink_pps);
351
352static struct device_type sink_pps_type = {
353	.name = "pdo",
354	.release = pdo_release,
355	.groups = sink_pps_groups,
356};
357
358/* -------------------------------------------------------------------------- */
359
360static const char * const supply_name[] = {
361	[PDO_TYPE_FIXED] = "fixed_supply",
362	[PDO_TYPE_BATT]  = "battery",
363	[PDO_TYPE_VAR]	 = "variable_supply",
364};
365
366static const char * const apdo_supply_name[] = {
367	[APDO_TYPE_PPS]  = "programmable_supply",
368};
369
370static struct device_type *source_type[] = {
371	[PDO_TYPE_FIXED] = &source_fixed_supply_type,
372	[PDO_TYPE_BATT]  = &source_battery_type,
373	[PDO_TYPE_VAR]   = &source_variable_supply_type,
374};
375
376static struct device_type *source_apdo_type[] = {
377	[APDO_TYPE_PPS]  = &source_pps_type,
378};
379
380static struct device_type *sink_type[] = {
381	[PDO_TYPE_FIXED] = &sink_fixed_supply_type,
382	[PDO_TYPE_BATT]  = &sink_battery_type,
383	[PDO_TYPE_VAR]   = &sink_variable_supply_type,
384};
385
386static struct device_type *sink_apdo_type[] = {
387	[APDO_TYPE_PPS]  = &sink_pps_type,
388};
389
390/* REVISIT: Export when EPR_*_Capabilities need to be supported. */
391static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position)
392{
393	struct device_type *type;
394	const char *name;
395	struct pdo *p;
396	int ret;
397
398	p = kzalloc(sizeof(*p), GFP_KERNEL);
399	if (!p)
400		return -ENOMEM;
401
402	p->pdo = pdo;
403	p->object_position = position;
404
405	if (pdo_type(pdo) == PDO_TYPE_APDO) {
406		/* FIXME: Only PPS supported for now! Skipping others. */
407		if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) {
408			dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo);
409			kfree(p);
410			return 0;
411		}
412
413		if (is_source(cap->role))
414			type = source_apdo_type[pdo_apdo_type(pdo)];
415		else
416			type = sink_apdo_type[pdo_apdo_type(pdo)];
417
418		name = apdo_supply_name[pdo_apdo_type(pdo)];
419	} else {
420		if (is_source(cap->role))
421			type = source_type[pdo_type(pdo)];
422		else
423			type = sink_type[pdo_type(pdo)];
424
425		name = supply_name[pdo_type(pdo)];
426	}
427
428	p->dev.parent = &cap->dev;
429	p->dev.type = type;
430	dev_set_name(&p->dev, "%u:%s", position + 1, name);
431
432	ret = device_register(&p->dev);
433	if (ret) {
434		put_device(&p->dev);
435		return ret;
436	}
437
438	return 0;
439}
440
441static int remove_pdo(struct device *dev, void *data)
442{
443	device_unregister(dev);
444	return 0;
445}
446
447/* -------------------------------------------------------------------------- */
448
449static const char * const cap_name[] = {
450	[TYPEC_SINK]    = "sink-capabilities",
451	[TYPEC_SOURCE]  = "source-capabilities",
452};
453
454static void pd_capabilities_release(struct device *dev)
455{
456	kfree(to_usb_power_delivery_capabilities(dev));
457}
458
459static struct device_type pd_capabilities_type = {
460	.name = "capabilities",
461	.release = pd_capabilities_release,
462};
463
464/**
465 * usb_power_delivery_register_capabilities - Register a set of capabilities.
466 * @pd: The USB PD instance that the capabilities belong to.
467 * @desc: Description of the Capablities Message.
468 *
469 * This function registers a Capabilities Message described in @desc. The
470 * capabilities will have their own sub-directory under @pd in sysfs.
471 *
472 * The function returns pointer to struct usb_power_delivery_capabilities, or
473 * ERR_PRT(errno).
474 */
475struct usb_power_delivery_capabilities *
476usb_power_delivery_register_capabilities(struct usb_power_delivery *pd,
477					 struct usb_power_delivery_capabilities_desc *desc)
478{
479	struct usb_power_delivery_capabilities *cap;
480	int ret;
481	int i;
482
483	cap = kzalloc(sizeof(*cap), GFP_KERNEL);
484	if (!cap)
485		return ERR_PTR(-ENOMEM);
486
487	cap->pd = pd;
488	cap->role = desc->role;
489
490	cap->dev.parent = &pd->dev;
491	cap->dev.type = &pd_capabilities_type;
492	dev_set_name(&cap->dev, "%s", cap_name[cap->role]);
493
494	ret = device_register(&cap->dev);
495	if (ret) {
496		put_device(&cap->dev);
497		return ERR_PTR(ret);
498	}
499
500	for (i = 0; i < PDO_MAX_OBJECTS && desc->pdo[i]; i++) {
501		ret = add_pdo(cap, desc->pdo[i], i);
502		if (ret) {
503			usb_power_delivery_unregister_capabilities(cap);
504			return ERR_PTR(ret);
505		}
506	}
507
508	return cap;
509}
510EXPORT_SYMBOL_GPL(usb_power_delivery_register_capabilities);
511
512/**
513 * usb_power_delivery_unregister_capabilities - Unregister a set of capabilities
514 * @cap: The capabilities
515 */
516void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap)
517{
518	if (!cap)
519		return;
520
521	device_for_each_child(&cap->dev, NULL, remove_pdo);
522	device_unregister(&cap->dev);
523}
524EXPORT_SYMBOL_GPL(usb_power_delivery_unregister_capabilities);
525
526/* -------------------------------------------------------------------------- */
527
528static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf)
529{
530	struct usb_power_delivery *pd = to_usb_power_delivery(dev);
531
532	return sysfs_emit(buf, "%u.%u\n", (pd->revision >> 8) & 0xff, (pd->revision >> 4) & 0xf);
533}
534static DEVICE_ATTR_RO(revision);
535
536static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
537{
538	struct usb_power_delivery *pd = to_usb_power_delivery(dev);
539
540	return sysfs_emit(buf, "%u.%u\n", (pd->version >> 8) & 0xff, (pd->version >> 4) & 0xf);
541}
542static DEVICE_ATTR_RO(version);
543
544static struct attribute *pd_attrs[] = {
545	&dev_attr_revision.attr,
546	&dev_attr_version.attr,
547	NULL
548};
549
550static umode_t pd_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
551{
552	struct usb_power_delivery *pd = to_usb_power_delivery(kobj_to_dev(kobj));
553
554	if (attr == &dev_attr_version.attr && !pd->version)
555		return 0;
556
557	return attr->mode;
558}
559
560static const struct attribute_group pd_group = {
561	.is_visible = pd_attr_is_visible,
562	.attrs = pd_attrs,
563};
564__ATTRIBUTE_GROUPS(pd);
565
566static void pd_release(struct device *dev)
567{
568	struct usb_power_delivery *pd = to_usb_power_delivery(dev);
569
570	ida_simple_remove(&pd_ida, pd->id);
571	kfree(pd);
572}
573
574static struct device_type pd_type = {
575	.name = "usb_power_delivery",
576	.release = pd_release,
577	.groups = pd_groups,
578};
579
580struct usb_power_delivery *usb_power_delivery_find(const char *name)
581{
582	struct device *dev;
583
584	dev = class_find_device_by_name(&pd_class, name);
585
586	return dev ? to_usb_power_delivery(dev) : NULL;
587}
588
589/**
590 * usb_power_delivery_register - Register USB Power Delivery Support.
591 * @parent: Parent device.
592 * @desc: Description of the USB PD contract.
593 *
594 * This routine can be used to register USB Power Delivery capabilities that a
595 * device or devices can support. These capabilities represent all the
596 * capabilities that can be negotiated with a partner, so not only the Power
597 * Capabilities that are negotiated using the USB PD Capabilities Message.
598 *
599 * The USB Power Delivery Support object that this routine generates can be used
600 * as the parent object for all the actual USB Power Delivery Messages and
601 * objects that can be negotiated with the partner.
602 *
603 * Returns handle to struct usb_power_delivery or ERR_PTR.
604 */
605struct usb_power_delivery *
606usb_power_delivery_register(struct device *parent, struct usb_power_delivery_desc *desc)
607{
608	struct usb_power_delivery *pd;
609	int ret;
610
611	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
612	if (!pd)
613		return ERR_PTR(-ENOMEM);
614
615	ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL);
616	if (ret < 0) {
617		kfree(pd);
618		return ERR_PTR(ret);
619	}
620
621	pd->id = ret;
622	pd->revision = desc->revision;
623	pd->version = desc->version;
624
625	pd->dev.parent = parent;
626	pd->dev.type = &pd_type;
627	pd->dev.class = &pd_class;
628	dev_set_name(&pd->dev, "pd%d", pd->id);
629
630	ret = device_register(&pd->dev);
631	if (ret) {
632		put_device(&pd->dev);
633		return ERR_PTR(ret);
634	}
635
636	return pd;
637}
638EXPORT_SYMBOL_GPL(usb_power_delivery_register);
639
640/**
641 * usb_power_delivery_unregister - Unregister USB Power Delivery Support.
642 * @pd: The USB PD contract.
643 */
644void usb_power_delivery_unregister(struct usb_power_delivery *pd)
645{
646	if (IS_ERR_OR_NULL(pd))
647		return;
648
649	device_unregister(&pd->dev);
650}
651EXPORT_SYMBOL_GPL(usb_power_delivery_unregister);
652
653/**
654 * usb_power_delivery_link_device - Link device to its USB PD object.
655 * @pd: The USB PD instance.
656 * @dev: The device.
657 *
658 * This function can be used to create a symlink named "usb_power_delivery" for
659 * @dev that points to @pd.
660 */
661int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev)
662{
663	int ret;
664
665	if (IS_ERR_OR_NULL(pd) || !dev)
666		return 0;
667
668	ret = sysfs_create_link(&dev->kobj, &pd->dev.kobj, "usb_power_delivery");
669	if (ret)
670		return ret;
671
672	get_device(&pd->dev);
673	get_device(dev);
674
675	return 0;
676}
677EXPORT_SYMBOL_GPL(usb_power_delivery_link_device);
678
679/**
680 * usb_power_delivery_unlink_device - Unlink device from its USB PD object.
681 * @pd: The USB PD instance.
682 * @dev: The device.
683 *
684 * Remove the symlink that was previously created with pd_link_device().
685 */
686void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev)
687{
688	if (IS_ERR_OR_NULL(pd) || !dev)
689		return;
690
691	sysfs_remove_link(&dev->kobj, "usb_power_delivery");
692	put_device(&pd->dev);
693	put_device(dev);
694}
695EXPORT_SYMBOL_GPL(usb_power_delivery_unlink_device);
696
697/* -------------------------------------------------------------------------- */
698
699int __init usb_power_delivery_init(void)
700{
701	return class_register(&pd_class);
702}
703
704void __exit usb_power_delivery_exit(void)
705{
706	ida_destroy(&pd_ida);
707	class_unregister(&pd_class);
708}