// SPDX-License-Identifier: GPL-2.0/* * USB Power Delivery sysfs entries * * Copyright (C) 2022, Intel Corporation * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> */ #include <linux/slab.h>#include <linux/usb/pd.h> #include "pd.h" static DEFINE_IDA(pd_ida); static struct class pd_class = { .name = "usb_power_delivery",}; #define to_pdo(o) container_of(o, struct pdo, dev) struct pdo { struct device dev; int object_position; u32 pdo;}; static void pdo_release(struct device *dev){ kfree(to_pdo(dev));} /* -------------------------------------------------------------------------- *//* Fixed Supply */ static ssize_tdual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE));}static DEVICE_ATTR_RO(dual_role_power); static ssize_tusb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND));}static DEVICE_ATTR_RO(usb_suspend_supported); static ssize_thigher_capability_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_HIGHER_CAP));}static DEVICE_ATTR_RO(higher_capability); static ssize_tunconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER));}static DEVICE_ATTR_RO(unconstrained_power); static ssize_tusb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM));}static DEVICE_ATTR_RO(usb_communication_capable); static ssize_tdual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP));}static DEVICE_ATTR_RO(dual_role_data); static ssize_tunchunked_extended_messages_supported_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT));}static DEVICE_ATTR_RO(unchunked_extended_messages_supported); static ssize_tpeak_current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", (to_pdo(dev)->pdo >> PDO_FIXED_PEAK_CURR_SHIFT) & 3);}static DEVICE_ATTR_RO(peak_current); static ssize_tfast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", (to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3);}static DEVICE_ATTR_RO(fast_role_swap_current); static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo));}static DEVICE_ATTR_RO(voltage); /* Shared with Variable supplies, both source and sink */static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo));} /* Shared with Variable type supplies */static struct device_attribute maximum_current_attr = { .attr = { .name = "maximum_current", .mode = 0444, }, .show = current_show,}; static struct device_attribute operational_current_attr = { .attr = { .name = "operational_current", .mode = 0444, }, .show = current_show,}; static struct attribute *source_fixed_supply_attrs[] = { &dev_attr_dual_role_power.attr, &dev_attr_usb_suspend_supported.attr, &dev_attr_unconstrained_power.attr, &dev_attr_usb_communication_capable.attr, &dev_attr_dual_role_data.attr, &dev_attr_unchunked_extended_messages_supported.attr, &dev_attr_peak_current.attr, &dev_attr_voltage.attr, &maximum_current_attr.attr, NULL}; static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n){ if (to_pdo(kobj_to_dev(kobj))->object_position && attr != &dev_attr_peak_current.attr && attr != &dev_attr_voltage.attr && attr != &maximum_current_attr.attr && attr != &operational_current_attr.attr) return 0; return attr->mode;} static const struct attribute_group source_fixed_supply_group = { .is_visible = fixed_attr_is_visible, .attrs = source_fixed_supply_attrs,};__ATTRIBUTE_GROUPS(source_fixed_supply); static const struct device_type source_fixed_supply_type = { .name = "pdo", .release = pdo_release, .groups = source_fixed_supply_groups,}; static struct attribute *sink_fixed_supply_attrs[] = { &dev_attr_dual_role_power.attr, &dev_attr_higher_capability.attr, &dev_attr_unconstrained_power.attr, &dev_attr_usb_communication_capable.attr, &dev_attr_dual_role_data.attr, &dev_attr_unchunked_extended_messages_supported.attr, &dev_attr_fast_role_swap_current.attr, &dev_attr_voltage.attr, &operational_current_attr.attr, NULL}; static const struct attribute_group sink_fixed_supply_group = { .is_visible = fixed_attr_is_visible, .attrs = sink_fixed_supply_attrs,};__ATTRIBUTE_GROUPS(sink_fixed_supply); static const struct device_type sink_fixed_supply_type = { .name = "pdo", .release = pdo_release, .groups = sink_fixed_supply_groups,}; /* -------------------------------------------------------------------------- *//* Variable Supply */ static ssize_tmaximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo));}static DEVICE_ATTR_RO(maximum_voltage); static ssize_tminimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo));}static DEVICE_ATTR_RO(minimum_voltage); static struct attribute *source_variable_supply_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &maximum_current_attr.attr, NULL};ATTRIBUTE_GROUPS(source_variable_supply); static const struct device_type source_variable_supply_type = { .name = "pdo", .release = pdo_release, .groups = source_variable_supply_groups,}; static struct attribute *sink_variable_supply_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &operational_current_attr.attr, NULL};ATTRIBUTE_GROUPS(sink_variable_supply); static const struct device_type sink_variable_supply_type = { .name = "pdo", .release = pdo_release, .groups = sink_variable_supply_groups,}; /* -------------------------------------------------------------------------- *//* Battery */ static ssize_tmaximum_power_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo));}static DEVICE_ATTR_RO(maximum_power); static ssize_toperational_power_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo));}static DEVICE_ATTR_RO(operational_power); static struct attribute *source_battery_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &dev_attr_maximum_power.attr, NULL};ATTRIBUTE_GROUPS(source_battery); static const struct device_type source_battery_type = { .name = "pdo", .release = pdo_release, .groups = source_battery_groups,}; static struct attribute *sink_battery_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &dev_attr_operational_power.attr, NULL};ATTRIBUTE_GROUPS(sink_battery); static const struct device_type sink_battery_type = { .name = "pdo", .release = pdo_release, .groups = sink_battery_groups,}; /* -------------------------------------------------------------------------- *//* Standard Power Range (SPR) Programmable Power Supply (PPS) */ static ssize_tpps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27)));}static DEVICE_ATTR_RO(pps_power_limited); static ssize_tpps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo));} static ssize_tpps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo));} static ssize_tpps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo));} static struct device_attribute pps_max_voltage_attr = { .attr = { .name = "maximum_voltage", .mode = 0444, }, .show = pps_max_voltage_show,}; static struct device_attribute pps_min_voltage_attr = { .attr = { .name = "minimum_voltage", .mode = 0444, }, .show = pps_min_voltage_show,}; static struct device_attribute pps_max_current_attr = { .attr = { .name = "maximum_current", .mode = 0444, }, .show = pps_max_current_show,}; static struct attribute *source_pps_attrs[] = { &dev_attr_pps_power_limited.attr, &pps_max_voltage_attr.attr, &pps_min_voltage_attr.attr, &pps_max_current_attr.attr, NULL};ATTRIBUTE_GROUPS(source_pps); static const struct device_type source_pps_type = { .name = "pdo", .release = pdo_release, .groups = source_pps_groups,}; static struct attribute *sink_pps_attrs[] = { &pps_max_voltage_attr.attr, &pps_min_voltage_attr.attr, &pps_max_current_attr.attr, NULL};ATTRIBUTE_GROUPS(sink_pps); static const struct device_type sink_pps_type = { .name = "pdo", .release = pdo_release, .groups = sink_pps_groups,}; /* -------------------------------------------------------------------------- *//* Standard Power Range (SPR) Adjustable Voltage Supply (AVS) */ static ssize_tspr_avs_9v_to_15v_max_current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umA\n", pdo_spr_avs_apdo_9v_to_15v_max_current_ma(to_pdo(dev)->pdo));} static ssize_tspr_avs_15v_to_20v_max_current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%umA\n", pdo_spr_avs_apdo_15v_to_20v_max_current_ma(to_pdo(dev)->pdo));} static ssize_tspr_avs_src_peak_current_show(struct device *dev, struct device_attribute *attr, char *buf){ return sysfs_emit(buf, "%u\n", pdo_spr_avs_apdo_src_peak_current(to_pdo(dev)->pdo));} static struct device_attribute spr_avs_9v_to_15v_max_current_attr = { .attr = { .name = "maximum_current_9V_to_15V", .mode = 0444, }, .show = spr_avs_9v_to_15v_max_current_show,}; static struct device_attribute spr_avs_15v_to_20v_max_current_attr = { .attr = { .name = "maximum_current_15V_to_20V", .mode = 0444, }, .show = spr_avs_15v_to_20v_max_current_show,}; static struct device_attribute spr_avs_src_peak_current_attr = { .attr = { .name = "peak_current", .mode = 0444, }, .show = spr_avs_src_peak_current_show,}; static struct attribute *source_spr_avs_attrs[] = { &spr_avs_9v_to_15v_max_current_attr.attr, &spr_avs_15v_to_20v_max_current_attr.attr, &spr_avs_src_peak_current_attr.attr, NULL};ATTRIBUTE_GROUPS(source_spr_avs); static const struct device_type source_spr_avs_type = { .name = "pdo", .release = pdo_release, .groups = source_spr_avs_groups,}; static struct attribute *sink_spr_avs_attrs[] = { &spr_avs_9v_to_15v_max_current_attr.attr, &spr_avs_15v_to_20v_max_current_attr.attr, NULL};ATTRIBUTE_GROUPS(sink_spr_avs); static const struct device_type sink_spr_avs_type = { .name = "pdo", .release = pdo_release, .groups = sink_spr_avs_groups,}; /* -------------------------------------------------------------------------- */ static const char * const supply_name[] = { [PDO_TYPE_FIXED] = "fixed_supply", [PDO_TYPE_BATT] = "battery", [PDO_TYPE_VAR] = "variable_supply",}; static const char * const apdo_supply_name[] = { [APDO_TYPE_PPS] = "programmable_supply", [APDO_TYPE_SPR_AVS] = "spr_adjustable_voltage_supply",}; static const struct device_type *source_type[] = { [PDO_TYPE_FIXED] = &source_fixed_supply_type, [PDO_TYPE_BATT] = &source_battery_type, [PDO_TYPE_VAR] = &source_variable_supply_type,}; static const struct device_type *source_apdo_type[] = { [APDO_TYPE_PPS] = &source_pps_type, [APDO_TYPE_SPR_AVS] = &source_spr_avs_type,}; static const struct device_type *sink_type[] = { [PDO_TYPE_FIXED] = &sink_fixed_supply_type, [PDO_TYPE_BATT] = &sink_battery_type, [PDO_TYPE_VAR] = &sink_variable_supply_type,}; static const struct device_type *sink_apdo_type[] = { [APDO_TYPE_PPS] = &sink_pps_type, [APDO_TYPE_SPR_AVS] = &sink_spr_avs_type,}; /* REVISIT: Export when EPR_*_Capabilities need to be supported. */static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position){ const struct device_type *type; const char *name; struct pdo *p; int ret; p = kzalloc_obj(*p); if (!p) return -ENOMEM; p->pdo = pdo; p->object_position = position; if (pdo_type(pdo) == PDO_TYPE_APDO) { /* * FIXME: Only PPS, SPR_AVS supported for now! * Skipping others. */ if (pdo_apdo_type(pdo) != APDO_TYPE_PPS && pdo_apdo_type(pdo) != APDO_TYPE_SPR_AVS) { dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo); kfree(p); return 0; }Lines 1–500 of 797. Load more
// SPDX-License-Identifier: GPL-2.0 /* * USB Power Delivery sysfs entries * * Copyright (C) 2022, Intel Corporation * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> */ #include <linux/slab.h> #include <linux/usb/pd.h> #include "pd.h" static DEFINE_IDA(pd_ida); static struct class pd_class = { .name = "usb_power_delivery", }; #define to_pdo(o) container_of(o, struct pdo, dev) struct pdo { struct device dev; int object_position; u32 pdo; }; static void pdo_release(struct device *dev) { kfree(to_pdo(dev)); } /* -------------------------------------------------------------------------- */ /* Fixed Supply */ static ssize_t dual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE)); } static DEVICE_ATTR_RO(dual_role_power); static ssize_t usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND)); } static DEVICE_ATTR_RO(usb_suspend_supported); static ssize_t higher_capability_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_HIGHER_CAP)); } static DEVICE_ATTR_RO(higher_capability); static ssize_t unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER)); } static DEVICE_ATTR_RO(unconstrained_power); static ssize_t usb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM)); } static DEVICE_ATTR_RO(usb_communication_capable); static ssize_t dual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP)); } static DEVICE_ATTR_RO(dual_role_data); static ssize_t unchunked_extended_messages_supported_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT)); } static DEVICE_ATTR_RO(unchunked_extended_messages_supported); static ssize_t peak_current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", (to_pdo(dev)->pdo >> PDO_FIXED_PEAK_CURR_SHIFT) & 3); } static DEVICE_ATTR_RO(peak_current); static ssize_t fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", (to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3); } static DEVICE_ATTR_RO(fast_role_swap_current); static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo)); } static DEVICE_ATTR_RO(voltage); /* Shared with Variable supplies, both source and sink */ static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo)); } /* Shared with Variable type supplies */ static struct device_attribute maximum_current_attr = { .attr = { .name = "maximum_current", .mode = 0444, }, .show = current_show, }; static struct device_attribute operational_current_attr = { .attr = { .name = "operational_current", .mode = 0444, }, .show = current_show, }; static struct attribute *source_fixed_supply_attrs[] = { &dev_attr_dual_role_power.attr, &dev_attr_usb_suspend_supported.attr, &dev_attr_unconstrained_power.attr, &dev_attr_usb_communication_capable.attr, &dev_attr_dual_role_data.attr, &dev_attr_unchunked_extended_messages_supported.attr, &dev_attr_peak_current.attr, &dev_attr_voltage.attr, &maximum_current_attr.attr, NULL }; static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { if (to_pdo(kobj_to_dev(kobj))->object_position && attr != &dev_attr_peak_current.attr && attr != &dev_attr_voltage.attr && attr != &maximum_current_attr.attr && attr != &operational_current_attr.attr) return 0; return attr->mode; } static const struct attribute_group source_fixed_supply_group = { .is_visible = fixed_attr_is_visible, .attrs = source_fixed_supply_attrs, }; __ATTRIBUTE_GROUPS(source_fixed_supply); static const struct device_type source_fixed_supply_type = { .name = "pdo", .release = pdo_release, .groups = source_fixed_supply_groups, }; static struct attribute *sink_fixed_supply_attrs[] = { &dev_attr_dual_role_power.attr, &dev_attr_higher_capability.attr, &dev_attr_unconstrained_power.attr, &dev_attr_usb_communication_capable.attr, &dev_attr_dual_role_data.attr, &dev_attr_unchunked_extended_messages_supported.attr, &dev_attr_fast_role_swap_current.attr, &dev_attr_voltage.attr, &operational_current_attr.attr, NULL }; static const struct attribute_group sink_fixed_supply_group = { .is_visible = fixed_attr_is_visible, .attrs = sink_fixed_supply_attrs, }; __ATTRIBUTE_GROUPS(sink_fixed_supply); static const struct device_type sink_fixed_supply_type = { .name = "pdo", .release = pdo_release, .groups = sink_fixed_supply_groups, }; /* -------------------------------------------------------------------------- */ /* Variable Supply */ static ssize_t maximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo)); } static DEVICE_ATTR_RO(maximum_voltage); static ssize_t minimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo)); } static DEVICE_ATTR_RO(minimum_voltage); static struct attribute *source_variable_supply_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &maximum_current_attr.attr, NULL }; ATTRIBUTE_GROUPS(source_variable_supply); static const struct device_type source_variable_supply_type = { .name = "pdo", .release = pdo_release, .groups = source_variable_supply_groups, }; static struct attribute *sink_variable_supply_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &operational_current_attr.attr, NULL }; ATTRIBUTE_GROUPS(sink_variable_supply); static const struct device_type sink_variable_supply_type = { .name = "pdo", .release = pdo_release, .groups = sink_variable_supply_groups, }; /* -------------------------------------------------------------------------- */ /* Battery */ static ssize_t maximum_power_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); } static DEVICE_ATTR_RO(maximum_power); static ssize_t operational_power_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); } static DEVICE_ATTR_RO(operational_power); static struct attribute *source_battery_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &dev_attr_maximum_power.attr, NULL }; ATTRIBUTE_GROUPS(source_battery); static const struct device_type source_battery_type = { .name = "pdo", .release = pdo_release, .groups = source_battery_groups, }; static struct attribute *sink_battery_attrs[] = { &dev_attr_maximum_voltage.attr, &dev_attr_minimum_voltage.attr, &dev_attr_operational_power.attr, NULL }; ATTRIBUTE_GROUPS(sink_battery); static const struct device_type sink_battery_type = { .name = "pdo", .release = pdo_release, .groups = sink_battery_groups, }; /* -------------------------------------------------------------------------- */ /* Standard Power Range (SPR) Programmable Power Supply (PPS) */ static ssize_t pps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27))); } static DEVICE_ATTR_RO(pps_power_limited); static ssize_t pps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo)); } static ssize_t pps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo)); } static ssize_t pps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo)); } static struct device_attribute pps_max_voltage_attr = { .attr = { .name = "maximum_voltage", .mode = 0444, }, .show = pps_max_voltage_show, }; static struct device_attribute pps_min_voltage_attr = { .attr = { .name = "minimum_voltage", .mode = 0444, }, .show = pps_min_voltage_show, }; static struct device_attribute pps_max_current_attr = { .attr = { .name = "maximum_current", .mode = 0444, }, .show = pps_max_current_show, }; static struct attribute *source_pps_attrs[] = { &dev_attr_pps_power_limited.attr, &pps_max_voltage_attr.attr, &pps_min_voltage_attr.attr, &pps_max_current_attr.attr, NULL }; ATTRIBUTE_GROUPS(source_pps); static const struct device_type source_pps_type = { .name = "pdo", .release = pdo_release, .groups = source_pps_groups, }; static struct attribute *sink_pps_attrs[] = { &pps_max_voltage_attr.attr, &pps_min_voltage_attr.attr, &pps_max_current_attr.attr, NULL }; ATTRIBUTE_GROUPS(sink_pps); static const struct device_type sink_pps_type = { .name = "pdo", .release = pdo_release, .groups = sink_pps_groups, }; /* -------------------------------------------------------------------------- */ /* Standard Power Range (SPR) Adjustable Voltage Supply (AVS) */ static ssize_t spr_avs_9v_to_15v_max_current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umA\n", pdo_spr_avs_apdo_9v_to_15v_max_current_ma(to_pdo(dev)->pdo)); } static ssize_t spr_avs_15v_to_20v_max_current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%umA\n", pdo_spr_avs_apdo_15v_to_20v_max_current_ma(to_pdo(dev)->pdo)); } static ssize_t spr_avs_src_peak_current_show(struct device *dev, struct device_attribute *attr, char *buf) { return sysfs_emit(buf, "%u\n", pdo_spr_avs_apdo_src_peak_current(to_pdo(dev)->pdo)); } static struct device_attribute spr_avs_9v_to_15v_max_current_attr = { .attr = { .name = "maximum_current_9V_to_15V", .mode = 0444, }, .show = spr_avs_9v_to_15v_max_current_show, }; static struct device_attribute spr_avs_15v_to_20v_max_current_attr = { .attr = { .name = "maximum_current_15V_to_20V", .mode = 0444, }, .show = spr_avs_15v_to_20v_max_current_show, }; static struct device_attribute spr_avs_src_peak_current_attr = { .attr = { .name = "peak_current", .mode = 0444, }, .show = spr_avs_src_peak_current_show, }; static struct attribute *source_spr_avs_attrs[] = { &spr_avs_9v_to_15v_max_current_attr.attr, &spr_avs_15v_to_20v_max_current_attr.attr, &spr_avs_src_peak_current_attr.attr, NULL }; ATTRIBUTE_GROUPS(source_spr_avs); static const struct device_type source_spr_avs_type = { .name = "pdo", .release = pdo_release, .groups = source_spr_avs_groups, }; static struct attribute *sink_spr_avs_attrs[] = { &spr_avs_9v_to_15v_max_current_attr.attr, &spr_avs_15v_to_20v_max_current_attr.attr, NULL }; ATTRIBUTE_GROUPS(sink_spr_avs); static const struct device_type sink_spr_avs_type = { .name = "pdo", .release = pdo_release, .groups = sink_spr_avs_groups, }; /* -------------------------------------------------------------------------- */ static const char * const supply_name[] = { [PDO_TYPE_FIXED] = "fixed_supply", [PDO_TYPE_BATT] = "battery", [PDO_TYPE_VAR] = "variable_supply", }; static const char * const apdo_supply_name[] = { [APDO_TYPE_PPS] = "programmable_supply", [APDO_TYPE_SPR_AVS] = "spr_adjustable_voltage_supply", }; static const struct device_type *source_type[] = { [PDO_TYPE_FIXED] = &source_fixed_supply_type, [PDO_TYPE_BATT] = &source_battery_type, [PDO_TYPE_VAR] = &source_variable_supply_type, }; static const struct device_type *source_apdo_type[] = { [APDO_TYPE_PPS] = &source_pps_type, [APDO_TYPE_SPR_AVS] = &source_spr_avs_type, }; static const struct device_type *sink_type[] = { [PDO_TYPE_FIXED] = &sink_fixed_supply_type, [PDO_TYPE_BATT] = &sink_battery_type, [PDO_TYPE_VAR] = &sink_variable_supply_type, }; static const struct device_type *sink_apdo_type[] = { [APDO_TYPE_PPS] = &sink_pps_type, [APDO_TYPE_SPR_AVS] = &sink_spr_avs_type, }; /* REVISIT: Export when EPR_*_Capabilities need to be supported. */ static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position) { const struct device_type *type; const char *name; struct pdo *p; int ret; p = kzalloc_obj(*p); if (!p) return -ENOMEM; p->pdo = pdo; p->object_position = position; if (pdo_type(pdo) == PDO_TYPE_APDO) { /* * FIXME: Only PPS, SPR_AVS supported for now! * Skipping others. */ if (pdo_apdo_type(pdo) != APDO_TYPE_PPS && pdo_apdo_type(pdo) != APDO_TYPE_SPR_AVS) { dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo); kfree(p); return 0; }