| /* |
| * ./kernel_modules/pse/pse-port.h |
| * |
| * This file provides the struct definitions for a PSE port |
| |
| * Author: Cradlepoint Technology, Inc. <source@cradlepoint.com> |
| * Kyle Swenson <kswenson@cradlepoint.com> |
| * |
| * Copyright 2017 Cradlepoint Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 |
| * as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| #ifndef __PSE_PORT_H__ |
| #define __PSE_PORT_H__ |
| |
| /* |
| *sys/class/pse/portX/ : |
| * class: |
| R: Last classification result |
| W: enable classification |
| * config: |
| R: Dump port config |
| * detect: |
| R: Last detection Result |
| W: Enable detection |
| * pd_current: |
| R: Current measurement at the port |
| * pd_voltage: |
| R: Voltage measurement at the port |
| * power: |
| W: "on" to power on a port |
| R: whether or not the port is powered |
| * reset: |
| W: Reset the port |
| * config: |
| * |
| */ |
| |
| #define PSE_PORT_NAME_SIZE 8 |
| #define PSE_PORT_PREFIX "port" |
| |
| /** |
| * struct pse_port_config - a configuration block for PSE ports |
| |
| |
| * @port_type: PSE_PORT_TYPE1 to configure af/at ( 15.4 W Max per port) |
| * PSE_PORT_TYPE2 to configure at+ (30 W Max per Port), |
| * PSE_PORT_TYPE3 for bt (Up to Class 6, 60W Max per port) |
| * PSE_PORT_TYPE4 for bt (Up to Class 8, 90W Max per port) |
| |
| * @managed: True if we are managing/configuring the port |
| * @enabled: False to shutdown the port |
| * @disconnect_event: Event on PD disconnection |
| * @detect_enable: Enable detection on the port |
| * @classify_enable: Enable classification on the port |
| * @current_limit: Set the port current limit (in mA), above which the port will be shut down. |
| */ |
| struct pse_port_config { |
| uint8_t enabled; |
| uint8_t managed; |
| uint8_t port_type; |
| uint8_t disconnect_event; |
| uint8_t detect_enable; |
| uint8_t classify_enable; |
| uint8_t legacy_enable; |
| uint8_t ping_pong_enable; |
| uint32_t current_limit; |
| }; |
| enum{ |
| PSE_PORT_TYPE1, |
| PSE_PORT_TYPE2, |
| PSE_PORT_TYPE3, |
| PSE_PORT_TYPE4, |
| }; |
| |
| enum { |
| DETECT_NO_DEVICE = 0, |
| DETECT_NORMAL_DEVICE, /* Short */ |
| DETECT_LEGACY_DEVICE, /* High cap devices */ |
| DETECT_POWERED_DEVICE,/* Signature resistance good */ |
| DETECT_ERROR, /* Port Voltage too high, open, rsig too low/rsig too high */ |
| PSE_NUM_DETECT_EVENTS /*This needs to be the last in this enum for bounds checking */ |
| }; |
| |
| enum { |
| CLASS_UNKNOWN = 0, |
| CLASS_1, |
| CLASS_2, |
| CLASS_3, |
| CLASS_4, |
| CLASS_5, /* Class 5, 4 Pair single signature */ |
| CLASS_6, /* Class 6, 4 Pair Single signature */ |
| CLASS_7, /* Class 7, 4 Pair Single signature */ |
| CLASS_8, /* Class 8, 4 Pair Single signature */ |
| CLASS_1D, /* Class 1, 4 Pair Dual signature (Class 1 allocation, independent per-pair) */ |
| CLASS_2D, /* Class 2, 4 Pair Dual signature (Class 2 allocation, independent per-pair) */ |
| CLASS_3D, |
| CLASS_4D, |
| CLASS_5D, /* Class 5, 4 Pair Dual Signature (90W same as class 8, 4 Pair Single )*/ |
| CLASS_INVALID, |
| PSE_NUM_CLASS_EVENTS/*This needs to be the last in this enum for bounds checking */ |
| }; |
| /** |
| * struct pse_port_ops - The set of operations of a PSE port. The PSE class will use these methods (if defined) to realize a PSE port |
| * @pd_voltage: Returns the voltage (in Volts) as measured at the port, |
| * negative on error. Used only for status update, not power budgeting. |
| * @pd_current: Returns the current (in mA) as measured at the port, negative |
| * on error. Used only for status updates, not power budgeting |
| * @last_detection:Returns the result of the last detection cycle on the port, |
| * negative on error. |
| * @last_classification: Returns the result of the last classification cycle on |
| * the port, negative on error |
| * @apply_power: Power a port. Returns "enable" on success, negative on error. |
| * @pd_powered: Return >0 if the port is currently powering a device; 0 if the |
| * port is NOT currently powering a device, and <0 on error |
| * @set_current_limit: Sets the current limit, in mA. If the port current |
| * exceeds this limit, the driver is responsible for shutting down the port |
| * (reset) and then send a PORT_DOWN event to the pse class |
| * @get_current_limit: Returns the port's currently configured current limit. |
| * @reset: Reset a port. If it was powering a device, unpower that device. |
| * Set the port to be in the same state as if it were just initialized |
| * @enable_detection: Allow a port to run (continuous) detection cycles |
| * @enable_classification: Allow a port to run classification cycles. |
| * @configure: Configure port parameters. |
| * @reset: Reset the pse port |
| */ |
| struct pse_port_ops { |
| int (*pd_voltage)(struct device *); |
| int (*pd_current)(struct device *); |
| int (*last_classification)(struct device *); |
| int (*last_detection)(struct device *); |
| int (*update_detection)(struct device *); |
| int (*update_classification)(struct device *); |
| int (*apply_power)(struct device *, unsigned enable); |
| int (*pd_powered)(struct device *); |
| int (*configure)(struct device *, struct pse_port_config *); |
| int (*status)(struct device *); |
| int (*get_config)(struct device *, struct pse_port_config *); |
| int (*reset)(struct device *); |
| int (*set_power_limit)(struct device *, int current_limit); |
| int (*get_power_limit)(struct device *); |
| int (*enable_detect)(struct device *, int enable); |
| int (*enable_classify)(struct device *, int enable); |
| }; |
| #define PORT_EVENT_DISCONNECT 0x01 |
| #define PORT_EVENT_DETECTED 0x02 |
| #define PORT_EVENT_CLASSIFIED 0x04 |
| |
| struct pse_port_device; |
| struct power_channel; |
| |
| struct power_channel { |
| uint8_t detect_result; /*One of DETECT values (below) */ |
| uint8_t class_result; |
| uint8_t connection_type; |
| uint8_t autoclass_result; |
| uint8_t id; /* The ID of this channel, range [0,3]. */ |
| struct pse_port_device *port; /* The port (Power Interface) that "contains" this power_channel */ |
| const struct pse_channel_ops *ops; |
| }; |
| enum { |
| CONNECTION_TYPE_UNKNOWN = 0, |
| CONNECTION_TYPE_SINGLE, |
| CONNECTION_TYPE_DUAL, |
| CONNECTION_TYPE_INVALID |
| }; |
| |
| static inline void power_channel_reset(struct power_channel *c) |
| { |
| c->detect_result = DETECT_NO_DEVICE; |
| c->class_result = CLASS_INVALID; |
| c->connection_type = CONNECTION_TYPE_INVALID; |
| c->autoclass_result = 0; |
| } |
| |
| /* Represent a "pse_port" |
| * Register this with the pse class |
| */ |
| struct pse_port_device { |
| struct device dev; |
| struct module *owner; |
| int ref_count; |
| int id; /* This ID is the X in /sys/class/pse/portX */ |
| uint8_t priority; /* Priority of the port, owned by the PSE Class */ |
| uint32_t power_allocation; /* Maximum power allocated for this port, owned by the PSE class */ |
| uint32_t power_request; /* Power requested by this port */ |
| uint32_t enabled; /* Should this port provide power? */ |
| struct power_channel *channel[2]; |
| |
| /* dual_signature devices have a maximum classification of 5 on each pair-set, |
| * and each channel is powered (or not) independently |
| */ |
| uint8_t dual_signature; |
| |
| /* This is the index of the port on the specific chip */ |
| uint8_t port_id; |
| uint8_t last_detect_result; |
| struct workqueue_struct *wq; |
| struct work_struct request_power; |
| struct work_struct disconnect; |
| uint8_t last_class_result; |
| const struct pse_port_ops *ops; |
| struct mutex lock; /* Intended to protect _this port's_ members */ |
| char name[PSE_PORT_NAME_SIZE]; |
| struct device *next_lp; /* The next lowest priority port */ |
| struct device *next_hp; /* The next highest priority port */ |
| }; |
| |
| static inline void pse_port_reset(struct pse_port_device *p) |
| { |
| power_channel_reset(p->channel[0]); |
| power_channel_reset(p->channel[1]); |
| p->last_class_result = CLASS_INVALID; |
| p->last_detect_result = DETECT_NO_DEVICE; |
| p->dual_signature = 0; |
| p->power_allocation = 0; |
| } |
| |
| #define to_pse_port_device(d) container_of(d, struct pse_port_device, dev) |
| #define to_ppd(dev) to_pse_port_device(dev) |
| |
| |
| |
| |
| |
| static inline void pse_port_set_clientdata(struct pse_port_device *port, void *userdata) |
| { |
| dev_set_drvdata(&port->dev, userdata); |
| } |
| static inline void *pse_port_get_clientdata(struct pse_port_device *port) |
| { |
| return dev_get_drvdata(&port->dev); |
| } |
| |
| |
| struct pse_port_device *pse_port_device_create(struct device *dev, const char *name, const struct pse_port_ops *ops, struct module *owner); |
| struct pse_port_device *pse_port_device_register(struct pse_port_device *pse_port); |
| void pse_port_device_unregister(struct pse_port_device *); |
| |
| extern char *pse_detect_strings[]; |
| extern char *pse_class_strings[]; |
| #endif |
| |