From 43a8dd13039fbf910c49f64fcffbe7391ceab596 Mon Sep 17 00:00:00 2001 From: jackcybertan Date: Fri, 27 Jun 2025 05:46:04 +0000 Subject: [PATCH] poe: add userland helpers scripts/tools Support user to control PSE on/off (chip: tps23861) via ucentral config file. Use uci-default to write poe's uci default file. Fixes: WIFI-14724 Signed-off-by: jackcybertan --- feeds/ucentral/poe/Makefile | 42 ++++ feeds/ucentral/poe/files/poe.config | 0 feeds/ucentral/poe/files/poe.init | 33 +++ feeds/ucentral/poe/src/Makefile | 26 +++ feeds/ucentral/poe/src/tps23861-poe-ctrl.c | 215 ++++++++++++++++++ .../files/etc/uci-defaults/99-ucentral-poe | 20 ++ profiles/sonicfi_rap630w-311g.yml | 1 + 7 files changed, 337 insertions(+) create mode 100644 feeds/ucentral/poe/Makefile create mode 100644 feeds/ucentral/poe/files/poe.config create mode 100644 feeds/ucentral/poe/files/poe.init create mode 100644 feeds/ucentral/poe/src/Makefile create mode 100644 feeds/ucentral/poe/src/tps23861-poe-ctrl.c create mode 100644 feeds/ucentral/ucentral-schema/files/etc/uci-defaults/99-ucentral-poe diff --git a/feeds/ucentral/poe/Makefile b/feeds/ucentral/poe/Makefile new file mode 100644 index 000000000..ef757edec --- /dev/null +++ b/feeds/ucentral/poe/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=poe +PKG_VERSION:=1.0 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +ifeq ($(CONFIG_TARGET_ipq50xx_generic_DEVICE_sonicfi_rap630w_311g),y) +TARGET_CFLAGS += -DPLATFORM_EWW631_B1=1 +endif + +define Package/poe + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Turn on/off PoE ports with TSP23861 chipset + DEPENDS:= +libubox +libubus +libuci +libi2c +endef + +define Package/poe/description + Turn on/off PoE ports +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + + +define Package/poe/install + $(INSTALL_DIR) $(1) + $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d + $(INSTALL_BIN) ./files/poe.init $(1)/etc/init.d/poe + $(INSTALL_BIN) ./files/poe.config $(1)/etc/config/poe + + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/tps23861-poe-ctrl $(1)/usr/bin +endef + +$(eval $(call BuildPackage,poe)) diff --git a/feeds/ucentral/poe/files/poe.config b/feeds/ucentral/poe/files/poe.config new file mode 100644 index 000000000..e69de29bb diff --git a/feeds/ucentral/poe/files/poe.init b/feeds/ucentral/poe/files/poe.init new file mode 100644 index 000000000..28b0f751d --- /dev/null +++ b/feeds/ucentral/poe/files/poe.init @@ -0,0 +1,33 @@ +#!/bin/sh /etc/rc.common + +START=10 + +tps23861_poe_ctrl () { + local section="$1" + local num mode + config_get num "$section" port_num + config_get mode "$section" admin_mode + + if [ "$mode" == "1" ]; then + output=$(tps23861-poe-ctrl -p "${num}" -P on) + echo "<6>${output}" > "/dev/kmsg" + else + output=$(tps23861-poe-ctrl -p "${num}" -P off) + echo "<6>${output}" > "/dev/kmsg" + fi +} + +start(){ + . /lib/functions.sh + + board=$(board_name) + case $board in + sonicfi,rap630w-311g|\ + cybertan,eww631-b1) + config_load poe + config_foreach tps23861_poe_ctrl port + ;; + *) + ;; + esac +} diff --git a/feeds/ucentral/poe/src/Makefile b/feeds/ucentral/poe/src/Makefile new file mode 100644 index 000000000..f3f224c28 --- /dev/null +++ b/feeds/ucentral/poe/src/Makefile @@ -0,0 +1,26 @@ +CFLAGS += -Wall -g + +INCLUDES = + +LDFLAGS = -lubus -lubox -li2c + +LIBS = + +SRCS = tps23861-poe-ctrl.c \ + +OBJS = $(SRCS:.c=.o) + +MAIN = tps23861-poe-ctrl + + +all: $(MAIN) + +$(MAIN): $(OBJS) + $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LDFLAGS) $(LIBS) + +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +clean: + $(RM) *.o *~ $(MAIN) $(TEST) + diff --git a/feeds/ucentral/poe/src/tps23861-poe-ctrl.c b/feeds/ucentral/poe/src/tps23861-poe-ctrl.c new file mode 100644 index 000000000..2c1fcf81a --- /dev/null +++ b/feeds/ucentral/poe/src/tps23861-poe-ctrl.c @@ -0,0 +1,215 @@ +/* + * User-space daemon formonitoring and managing PoE ports with + * TI TPS23861 chips. based on the Linux Kernel TPS23861 + * HWMON driver. +*/ + +#include /* Standard input/output definitions */ +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include /* File control definitions */ +#include /* Error number definitions */ +#include +#include +#include /* uapi/linux/i2c-dev.h */ + +#include + +#define TPS23861_I2C_ADDR 0x20 +#define DETECT_CLASS_RESTART 0x18 +#define POWER_ENABLE 0x19 +#define POWER_ON_SHIFT 0 +#define POWER_OFF_SHIFT 4 + +typedef unsigned char u8; + +#if defined(PLATFORM_EWW631_B1) +#define TPS23861_NUM_PORTS 1 +#endif + +#define CONVERT_PORT_NUM(x) (1 << ((u8)x-1)) + +unsigned int PORT_POWER_STATUS[TPS23861_NUM_PORTS]; + +int i2c_handler = -1; +#define ULOG_DBG(fmt, ...) ulog(LOG_DEBUG, fmt, ## __VA_ARGS__) + +int open_device(void) +{ + int fd, fset; + + fd = open("/dev/i2c-0", O_RDWR); + fset = fcntl(fd, F_SETFL, 0); + if (fset < 0) + printf("fcntl failed!\n"); + + //if (isatty(STDIN_FILENO) == 0) + // printf("standard input is not a terminal device\n"); + + return fd; +} + +int access_salve(int fd) +{ + int ret; + + if((ret = ioctl(fd, I2C_SLAVE, TPS23861_I2C_ADDR)) < 0) + { + printf("%s: Failed to access slave bus[%s]\n",__func__, strerror(errno)); + return -1; + } + return(ret); +} + +// Write to an I2C slave device's register: +int i2c_write(u8 slave_addr, u8 reg, u8 data) +{ + u8 outbuf[2]; + + struct i2c_msg msgs[1]; + struct i2c_rdwr_ioctl_data msgset[1]; + + outbuf[0] = reg; + outbuf[1] = data; + + msgs[0].addr = slave_addr; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = outbuf; + + msgset[0].msgs = msgs; + msgset[0].nmsgs = 1; + + if (ioctl(i2c_handler, I2C_RDWR, &msgset) < 0) { + perror("ioctl(I2C_RDWR) in i2c_write"); + return -1; + } + + return 0; +} + +void poe_set_PowerOnOff(u8 port, u8 on_off) { + u8 value; + u8 portBit; + portBit = CONVERT_PORT_NUM(port+1); + + if(on_off == 0) { + value = (portBit << POWER_OFF_SHIFT); + PORT_POWER_STATUS[port] = 0; + } else { + value = (portBit << POWER_ON_SHIFT); + PORT_POWER_STATUS[port] = 1; + } + + ULOG_DBG("set Port%d Power Status [%d] portBit 0x[%x] value 0x[%x]\n", port+1, PORT_POWER_STATUS[port], portBit, value); + + if(i2c_write(TPS23861_I2C_ADDR, POWER_ENABLE, value) < 0) + { + ULOG_ERR("Set port%d power on-off error (0x19)\n", port); + } +} + +void RestartPortDetectClass(u8 port) +{ + u8 value; + + value = (1 << port) | (1 << (port + 4)); + ULOG_DBG("RestartPortDetectClass value 0x%x\n", value); + if(i2c_write(TPS23861_I2C_ADDR, DETECT_CLASS_RESTART, value) < 0) { + ULOG_ERR("Set port%d detection and class on error\n",port); + } +} + +int usage(const char *progname) +{ + fprintf(stderr, "Usage: %s -p <1-3> -P [options]\n" + "Required options:\n" + " -p <1-3>: Select port number (Only port 1 is supported)\n" + " -P : Set PSE function state \n" + "Optional options:\n" + " -d Enable debug mode\n" + "\n", progname); + return 1; +} + +static int setPSE(int port ,char *optarg) +{ + int ret = 0; + i2c_handler = open_device(); + if (i2c_handler < 0) { + ULOG_ERR("open i2c-0 device error!\n"); + goto EXIT; + } + + ret = access_salve(i2c_handler); + if (ret < 0) + { + ULOG_ERR("The i2c-0 access error\n"); + goto EXIT; + } + + if(!strncmp("on", optarg, 2)) { + printf("Enable port%d PSE function\n", port); + RestartPortDetectClass(port-1); + } + else if (!strncmp("off", optarg, 3)) { + printf("Disable port%d PSE function\n", port); + poe_set_PowerOnOff(port-1, 0); + } + else { + ULOG_ERR("[Set] Do not accept this optarg!!!\n"); + ret = 1; + } +EXIT: + close(i2c_handler); + return ret; +} + +int main(int argc, char *argv[]) +{ + int ch, ret = 0, port = 0; + char *PSE = NULL; + if (argc == 1) { + return usage(argv[0]); + } + + + ulog_open(ULOG_STDIO | ULOG_SYSLOG, LOG_DAEMON, "tps23861"); + ulog_threshold(LOG_INFO); + + while ((ch = getopt(argc, argv, "dp:P:")) != -1) { + switch (ch) { + case 'd': + printf("tps23861-i2c-control ulog_threshold set to debug level\n"); + ulog_threshold(LOG_DEBUG); + break; + + case 'p': + port = atoi(optarg); + break; + + case 'P': + PSE = optarg; + break; + + default: + ret = usage(argv[0]); + break; + } + } + + if (port < 1 || port > 3) { + ret = usage(argv[0]); + } + else { + if (PSE) { + setPSE(port, PSE); + } + else { + ret = usage(argv[0]); + } + } + + return ret; + +} diff --git a/feeds/ucentral/ucentral-schema/files/etc/uci-defaults/99-ucentral-poe b/feeds/ucentral/ucentral-schema/files/etc/uci-defaults/99-ucentral-poe new file mode 100644 index 000000000..14ef4c11d --- /dev/null +++ b/feeds/ucentral/ucentral-schema/files/etc/uci-defaults/99-ucentral-poe @@ -0,0 +1,20 @@ +#!/bin/sh + +. /lib/functions.sh + +board=$(board_name) +case $board in + sonicfi,rap630w-311g|\ + cybertan,eww631-b1) + for num in $(seq 1 3) + do + uci add poe port + uci set poe.@port[-1]='port' + eval uci set poe.@port[-1].port_num='${num}' + uci set poe.@port[-1].admin_mode='1' + done + uci commit + ;; + *) + ;; +esac \ No newline at end of file diff --git a/profiles/sonicfi_rap630w-311g.yml b/profiles/sonicfi_rap630w-311g.yml index 4bc45b04d..977f99b69 100755 --- a/profiles/sonicfi_rap630w-311g.yml +++ b/profiles/sonicfi_rap630w-311g.yml @@ -10,5 +10,6 @@ feeds: packages: - ipq50xx - cooling + - poe include: - ucentral-ap