blob: 609c82295ce4c60ff03d989ea1cc506fe11beac7 [file] [log] [blame]
/*
* ./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