From patchwork Wed Jan 26 06:38:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Oskari_Lemmel=C3=A4?= X-Patchwork-Id: 1584368 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=ozXc8bnK; dkim=fail reason="signature verification failed" (4096-bit key; unprotected) header.d=lemmela.net header.i=@lemmela.net header.a=rsa-sha256 header.s=dkim header.b=oY8O0Vi4; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4JkDhF03Vnz9t6h for ; Wed, 26 Jan 2022 17:43:40 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=SJwNT2V3KKpORGZbUSCxz3wcxKtVg0xwaXAxRPh/ZH4=; b=ozXc8bnK2SJ496 R40aiG2H+808kAV072OiQah99DcIRFmSMzFupLJ8qQflmD6K8PRpKMft5t2DmQjppCZEwYnOK+eid SNWz9CnG8lwsx2kdpQ3ptXO5FATfgC8nukT6/CliO/n9RbHFIVizgioHzh6DTF6Rn/MkkQMQzZEjM Ss0bZDv4sbR2wcIx8FEMu9iBaMZY6iPCnLDPFmQLuFf+xSmsoMeK+1Xay5O8H5AQfgb1WiBtxRSLL 3mRG8cZrDRYOSFG+sYV8plXPfxi5pUemn9MsrMgLuk+qmMafxJb4sS7I7s9tGVM7IFDXvDF1oMBB2 RZ82J+ED3GOj/QXYTUpQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nCbyp-00AJV6-Lm; Wed, 26 Jan 2022 06:40:32 +0000 Received: from mail1.kuutio.org ([54.37.79.207]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nCbxY-00AJEK-AT for openwrt-devel@lists.openwrt.org; Wed, 26 Jan 2022 06:39:15 +0000 Received: from localhost (localhost [127.0.0.1]) by mail1.kuutio.org (Postfix) with ESMTP id 1899E1FD85; Wed, 26 Jan 2022 07:39:10 +0100 (CET) Authentication-Results: mail1.kuutio.org (amavisd-new); dkim=pass (4096-bit key) reason="pass (just generated, assumed good)" header.d=lemmela.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=lemmela.net; h= content-transfer-encoding:mime-version:references:in-reply-to :x-mailer:message-id:date:date:subject:subject:from:from :received:received; s=dkim; t=1643179145; x=1645771146; bh=4Wx5u UAadn6MFELaQdtaz6T0W+/h/pZ+fK3G2ipw98Y=; b=oY8O0Vi4yT9OEuD7H0CMH wBDDiifuGoSBmcqKCDlFOol91LIsSE25jiY6Fu7ux+1WCrxSAXGNLu8M8Kg/um/d fz9SC1TWlBc1ioWfWTAU5BcVEj3I/tQFeAKKbXw5B1dioZgmJ5FygFPXNvdvsS2o LtVSiX7kTakXdxX/kOx6d9/Az9K5qr3/XJx0eZNpD5UuYKMucfvi4+hVQtwIm8VW SOznpKDO3FdhVxJzSOBgjbwp6GgGHP0D8uwmmUI9YVqJnTnO12UseR8yM3FYHAlv JUgFmn7ZXIyefGSqLINujZSsvQ6S2HJCYDwKEANGubPssIWBVNID8cWsidbh9xcX C7rhw0N9JFh8Ct7Qtj0EQiFvlCaVJbKPT2ZYVyAObo7j+E0M1VtmrIlne/m46ltK iZT4VDwUJVJuwB4qw7WL2licwtVKbprEjMBiZUleOvgLIWF7avNySi9XT5tWH6Qg SlJ80ObJs801/VWKz7GQ76NGvYVSBoLBwyrfRBzOCp5Xvf95K/ZEMW5gFBkKmnpD FAx3arcN/8njDvzqxiPo50sqClvKhrYfDciGPWvdkBGgZt/hi6dkfkHuUBfvsYjD L1ic5Y/zzJtSiM54mFRfofRW2XSYR836rQmGeG/ETm6PvK5LMmXcOQ06xlf2L9mL 09tm8z4TPnTdZbjyAzhv0Q= X-Virus-Scanned: amavisd-new at kuutio.org Received: from mail1.kuutio.org ([127.0.0.1]) by localhost (mail1.kuutio.org [127.0.0.1]) (amavisd-new, port 10024) with LMTP id Xeqnco_rbhv4; Wed, 26 Jan 2022 07:39:05 +0100 (CET) Received: from build.kuutio.org (unknown [IPv6:2001:998:13:e4::69]) by mail1.kuutio.org (Postfix) with ESMTPSA id 234F71FDD0; Wed, 26 Jan 2022 07:39:01 +0100 (CET) From: Oskari Lemmela To: openwrt-devel@lists.openwrt.org Cc: Oskari Lemmela Subject: [PATCH 4/5] ath79: mikrotik: add poe driver Date: Wed, 26 Jan 2022 08:38:44 +0200 Message-Id: <20220126063845.587284-5-oskari@lemmela.net> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220126063845.587284-1-oskari@lemmela.net> References: <20220126063845.587284-1-oskari@lemmela.net> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220125_223912_779318_AB4DA857 X-CRM114-Status: GOOD ( 24.20 ) X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Add hwmon based driver for mikrotik POE controllers. Signed-off-by: Oskari Lemmela --- .../linux/ath79/files/drivers/hwmon/rbpoe.c | 256 ++++++++++++++ .../linux/ath79/files/drivers/hwmon/rbpoe.h | 25 ++ .../ath79/files/drivers/hwmo [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Add hwmon based driver for mikrotik POE controllers. Signed-off-by: Oskari Lemmela --- .../linux/ath79/files/drivers/hwmon/rbpoe.c | 256 ++++++++++++++ .../linux/ath79/files/drivers/hwmon/rbpoe.h | 25 ++ .../ath79/files/drivers/hwmon/rbpoeport.c | 311 ++++++++++++++++++ target/linux/ath79/mikrotik/config-default | 3 + .../902-hwmon-support-for-mikrotik-poe.patch | 51 +++ 5 files changed, 646 insertions(+) create mode 100644 target/linux/ath79/files/drivers/hwmon/rbpoe.c create mode 100644 target/linux/ath79/files/drivers/hwmon/rbpoe.h create mode 100644 target/linux/ath79/files/drivers/hwmon/rbpoeport.c create mode 100644 target/linux/ath79/patches-5.10/902-hwmon-support-for-mikrotik-poe.patch diff --git a/target/linux/ath79/files/drivers/hwmon/rbpoe.c b/target/linux/ath79/files/drivers/hwmon/rbpoe.c new file mode 100644 index 0000000000..fb5de6e6d7 --- /dev/null +++ b/target/linux/ath79/files/drivers/hwmon/rbpoe.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * Mikrotik POE driver + * + * Based on https://github.com/adron-s/mtpoe_ctrl + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rbpoe.h" + +DECLARE_CRC8_TABLE(rbpoe_crc_table); + +#define MAX_PORTS 4 + +int rb_poe_get_port_idx(struct rb_poe_data *poe, int reg) +{ + if (poe->data->reverse) + return (MAX_PORTS-reg); + else + return reg-1; +} +EXPORT_SYMBOL(rb_poe_get_port_idx); + +int rb_poe_write_cmd(struct rb_poe_data *poe, u16 *resp, u8 cmd, u8 arg1, u8 arg2) +{ + int ret; + u8 tx[4]; + u8 rx[6]; + u8 crc, retries; + + struct spi_transfer xfers[] = { + { + .tx_buf = tx, + .len = 4, + .delay.value = 10, + .delay.unit = SPI_DELAY_UNIT_USECS, + }, + { + .rx_buf = rx, + .len = 6, + }, + }; + + mutex_lock(&poe->lock); + + tx[0] = cmd; + tx[1] = arg1; + tx[2] = arg2; + tx[3] = crc8(rbpoe_crc_table, tx, 3, 0); + + for (retries = 0; retries < MAX_RETRIES; retries++) { + ret = spi_sync_transfer(poe->spi, xfers, ARRAY_SIZE(xfers)); + if (ret < 0) { + dev_err(&poe->spi->dev, "SPI transfer error"); + goto out; + } + + if (rx[1] != cmd) { + ndelay(13); + continue; + } + + crc = crc8(rbpoe_crc_table, rx+1, 3, 0); + + if (rx[4] != crc && rx[5] != crc) + continue; + + resp[0] = rx[2] << 8 | rx[3]; + goto out; + } +out: + mutex_unlock(&poe->lock); + return ret; +} +EXPORT_SYMBOL(rb_poe_write_cmd); + +static int rb_poe_read_version(struct rb_poe_data *data) +{ + int ret; + u16 vers; + + ret = rb_poe_write_cmd(data, &vers, 0x41, 0, 0); + if (ret < 0) + return ret; + return vers; +} + +int rb_poe_read_voltage(struct rb_poe_data *data) +{ + int ret; + u16 val; + + ret = rb_poe_write_cmd(data, &val, 0x42, 0, 0); + if (ret < 0) + return ret; + return val * data->data->volt_lsb; +} +EXPORT_SYMBOL(rb_poe_read_voltage); + +static int rb_poe_read_temperature(struct rb_poe_data *data) +{ + int ret; + u16 val; + + ret = rb_poe_write_cmd(data, &val, 0x43, 0, 0); + if (ret < 0) + return ret; + return (val * data->data->temp_lsb) - data->data->temp_offset; +} + +/* sysfs attributes */ +static ssize_t temp_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rb_poe_data *data = dev_get_drvdata(dev); + int val; + + if (IS_ERR(data)) + return -ENODATA; + + val = rb_poe_read_temperature(data); + if (val < 0) + return -ENODATA; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t in_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rb_poe_data *data = dev_get_drvdata(dev); + int val; + + if (IS_ERR(data)) + return -ENODATA; + + val = rb_poe_read_voltage(data); + if (val < 0) + return -ENODATA; + + return sprintf(buf, "%d\n", val); +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0); +static SENSOR_DEVICE_ATTR_RO(in0_input, in_input, 4); + +static struct attribute *rb_poe_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + NULL +}; + +ATTRIBUTE_GROUPS(rb_poe); + +static int rb_poe_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct device *hwmon_dev; + struct rb_poe_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->data = (struct rb_poe_model *)of_device_get_match_data(dev); + data->spi = spi; + + spi->mode = SPI_MODE_0; + ret = spi_setup(spi); + if (ret) + return ret; + + crc8_populate_lsb(rbpoe_crc_table, 0x8C); + dev_set_drvdata(dev, data); + mutex_init(&data->lock); + + ret = rb_poe_read_version(data); + if (ret < 0) + return ret; + + dev_info(dev, "firmware: %d.%d", ret & 0xff, ret >> 8); + + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret < 0) { + dev_err(dev, "failed to populate DT children\n"); + return ret; + } + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, "rbpoe", data, rb_poe_groups); + + if (IS_ERR(hwmon_dev)) + dev_dbg(dev, "unable to register hwmon device\n"); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct rb_poe_model v2_data = { + .reverse = 1, + .volt_lsb = 35, + .temp_lsb = 1000, + .temp_offset = 273000, +}; + +/* + * ATSAMD20J15 temperature sensor factory calibration is done at 25C 667mV with Vddana=3.3V + * Typical sensor slope 2.4mV/C. 667mV/2.4mV/C = 277.917C - 25C = 253.917C + * Measured Vddana is 3.29V, reduce slope a bit and tune calibration vdd. + * 680mV/2.375mV/C = 286.315C - 25C = 261.315C + * 1000/2.375 = 421 + */ +static const struct rb_poe_model v3_data = { + .reverse = 0, + .volt_lsb = 10, + .temp_lsb = 421, + .temp_offset = 261315, +}; + +static const struct of_device_id rb_poe_dt_match[] = { + { + .compatible = "mikrotik,poe-v2", + .data = (void *)&v2_data, + }, { + .compatible = "mikrotik,poe-v3", + .data = (void *)&v3_data, + }, { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, rb_poe_dt_match); + +static struct spi_driver rb_poe_driver = { + .probe = rb_poe_probe, + .driver = { + .name = "rb-poe-driver", + .bus = &spi_bus_type, + .of_match_table = of_match_ptr(rb_poe_dt_match), + }, +}; + +module_spi_driver(rb_poe_driver); + +MODULE_AUTHOR("Oskari Lemmela "); +MODULE_DESCRIPTION("Mikrotik POE driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ath79/files/drivers/hwmon/rbpoe.h b/target/linux/ath79/files/drivers/hwmon/rbpoe.h new file mode 100644 index 0000000000..af1f59329f --- /dev/null +++ b/target/linux/ath79/files/drivers/hwmon/rbpoe.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * POE driver for the MikroTik RouterBoard series + */ +#include + +#define MAX_RETRIES 10 + +struct rb_poe_model { + bool reverse; + u8 volt_lsb; + u16 temp_lsb; + u32 temp_offset; +}; + +struct rb_poe_data { + struct spi_device *spi; + struct rb_poe_model *data; + + struct mutex lock; +}; + +int rb_poe_write_cmd(struct rb_poe_data *data, u16 *resp, u8 cmd, u8 arg1, u8 arg2); +int rb_poe_get_port_idx(struct rb_poe_data *data, int reg); +int rb_poe_read_voltage(struct rb_poe_data *data); diff --git a/target/linux/ath79/files/drivers/hwmon/rbpoeport.c b/target/linux/ath79/files/drivers/hwmon/rbpoeport.c new file mode 100644 index 0000000000..1b9852a0e7 --- /dev/null +++ b/target/linux/ath79/files/drivers/hwmon/rbpoeport.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * Mikrotik POE port driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rbpoe.h" + +#define PORT_DISABLED 0x0 +#define PORT_FORCE 0x1 +#define PORT_ENABLED 0x2 + +struct poeport_data { + struct rb_poe_data *poe; + struct device *dev; + + u8 state; + u8 force; + u32 reg; +}; + +static int read_state(struct poeport_data *port) +{ + int ret; + u16 status; + + ret = rb_poe_write_cmd(port->poe, &status, 0x45, 0, 0); + if (ret < 0) + return ret; + return status >> rb_poe_get_port_idx(port->poe, port->reg)*4 & 0xF; +} + +static int write_state(struct poeport_data *port, u8 state, u8 force) +{ + int ret; + u16 status; + + if (state) + if (force) + state = PORT_FORCE; + else + state = PORT_ENABLED; + else + state = PORT_DISABLED; + + ret = rb_poe_write_cmd(port->poe, &status, 0x44, port->reg, state); + if (ret < 0) { + usleep_range(100, 150); + ret = rb_poe_write_cmd(port->poe, &status, 0x44, port->reg, state); + } + return ret; +} + +static int read_current(struct poeport_data *port) +{ + int ret; + u16 curr; + + ret = rb_poe_write_cmd(port->poe, &curr, 0x58+port->reg, 0, 0); + if (ret < 0) + return ret; + return curr; +} + +/* sysfs attributes */ +static ssize_t in_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct poeport_data *data = dev_get_drvdata(dev); + int state, curr; + + if (IS_ERR(data)) + return PTR_ERR(data); + + state = read_state(data); + if (state < 0 || state == PORT_DISABLED) + return -ENODATA; + + curr = read_current(data); + if (curr < 0 || (state == PORT_ENABLED && curr >> 15)) + return -ENODATA; + + return sprintf(buf, "%d\n", rb_poe_read_voltage(data->poe)); +} + +static ssize_t force_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct poeport_data *data = dev_get_drvdata(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->force); +} + +static ssize_t force_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct poeport_data *data = dev_get_drvdata(dev); + int ret; + int state; + + ret = kstrtoint(buf, 0, &state); + if (ret) + return ret; + + data->force = state; + ret = write_state(data, data->state, state); + if (ret) + return ret; + return count; +} + +static ssize_t port_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct poeport_data *data = dev_get_drvdata(dev); + int curr; + + if (IS_ERR(data)) + return PTR_ERR(data); + + if (!data->state) + return sprintf(buf, "disabled\n"); + + curr = read_current(data); + if (curr == 0x800A) + return sprintf(buf, "short circuit\n"); + if (!data->force && curr >> 15) + return sprintf(buf, "searching\n"); + if (curr < 3) + return sprintf(buf, "no load\n"); + + return sprintf(buf, "delivering\n"); + +} + +static ssize_t in_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct poeport_data *data = dev_get_drvdata(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return sprintf(buf, "%d\n", data->state); +} + +static ssize_t in_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct poeport_data *data = dev_get_drvdata(dev); + int ret; + int state; + + ret = kstrtoint(buf, 0, &state); + if (ret) + return ret; + + data->state = state; + ret = write_state(data, state, data->force); + if (ret) + return ret; + + return count; +} + +static ssize_t curr_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct poeport_data *data = dev_get_drvdata(dev); + int curr; + + if (IS_ERR(data)) + return PTR_ERR(data); + + curr = read_current(data); + if (curr < 0 || curr >> 15) + return -ENODATA; + + return sprintf(buf, "%d\n", curr); +} + +static ssize_t power_input_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct poeport_data *data = dev_get_drvdata(dev); + int volt, curr; + + if (IS_ERR(data)) + return PTR_ERR(data); + + curr = read_current(data); + if (curr < 0 || curr >> 15) + return -ENODATA; + + volt = rb_poe_read_voltage(data->poe); + if (volt < 0) + return -ENODATA; + + return sprintf(buf, "%d\n", curr*volt); +} + +static SENSOR_DEVICE_ATTR_RO(curr1_input, curr_input, 0); +static SENSOR_DEVICE_ATTR_RO(power1_input, power_input, 0); +static SENSOR_DEVICE_ATTR_RW(in1_enable, in_enable, 0); +static SENSOR_DEVICE_ATTR_RO(in1_input, in_input, 0); +static SENSOR_DEVICE_ATTR_RW(force_enable, force_enable, 0); +static SENSOR_DEVICE_ATTR_RO(port_state, port_state, 0); + +static struct attribute *rb_poeport_attrs[] = { + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_in1_enable.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_force_enable.dev_attr.attr, + &sensor_dev_attr_port_state.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(rb_poeport); + +static int rb_poeport_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *hwmon_dev; + struct poeport_data *data; + const char *label; + int ret, val; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + + ret = of_property_read_u32(dev->of_node, "reg", &val); + if (ret < 0) { + dev_err(dev, "missing 'reg' property (%d)\n", ret); + return ret; + } + + data->reg = val; + + if (of_property_read_string(dev->of_node, "label", &label) < 0) + label = "poeport"; + + if (!dev->parent) { + dev_err(dev, "no ctrl device\n"); + return -ENODEV; + } + + data->poe = dev_get_drvdata(dev->parent); + + switch (read_state(data)) { + case PORT_FORCE: + data->force = 1; + data->state = 1; + break; + case PORT_ENABLED: + data->force = 0; + data->state = 1; + break; + case PORT_DISABLED: + data->state = 0; + data->force = 0; + } + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, label, data, rb_poeport_groups); + + if (IS_ERR(hwmon_dev)) + dev_dbg(dev, "unable to register hwmon device\n"); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id rb_poeport_of_match[] = { + { .compatible = "mikrotik,poeport" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, rb_poeport_of_match); + +static struct platform_driver rb_poeport_driver = { + .probe = rb_poeport_probe, + .driver = { + .name = "rb-poeport-driver", + .of_match_table = of_match_ptr(rb_poeport_of_match), + }, +}; + +module_platform_driver(rb_poeport_driver); + +MODULE_AUTHOR("Oskari Lemmela "); +MODULE_DESCRIPTION("Mikrotik poeport driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/ath79/mikrotik/config-default b/target/linux/ath79/mikrotik/config-default index 175c4fac1f..8348998421 100644 --- a/target/linux/ath79/mikrotik/config-default +++ b/target/linux/ath79/mikrotik/config-default @@ -7,6 +7,7 @@ CONFIG_GPIO_RB91X_KEY=y CONFIG_GPIO_RB4XX=y CONFIG_GPIO_WATCHDOG=y CONFIG_GPIO_WATCHDOG_ARCH_INITCALL=y +CONFIG_HWMON=y CONFIG_LEDS_RESET=y CONFIG_LZO_DECOMPRESS=y CONFIG_MDIO_GPIO=y @@ -36,6 +37,8 @@ CONFIG_PCI_AR71XX=y CONFIG_PHY_AR7100_USB=y CONFIG_PHY_AR7200_USB=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_SENSORS_MIKROTIK_POE=y +CONFIG_SENSORS_MIKROTIK_POEPORT=y CONFIG_SPI_RB4XX=y CONFIG_UBIFS_FS=y CONFIG_WATCHDOG_CORE=y diff --git a/target/linux/ath79/patches-5.10/902-hwmon-support-for-mikrotik-poe.patch b/target/linux/ath79/patches-5.10/902-hwmon-support-for-mikrotik-poe.patch new file mode 100644 index 0000000000..ac33e2061c --- /dev/null +++ b/target/linux/ath79/patches-5.10/902-hwmon-support-for-mikrotik-poe.patch @@ -0,0 +1,51 @@ +From beb4c6b6e4c186ffaec860a7c5f83ff582c37413 Mon Sep 17 00:00:00 2001 +From: Oskari Lemmela +Date: Fri, 3 Dec 2021 15:28:49 +0200 +Subject: [PATCH] hwmon: support for mikrotik poe + +Signed-off-by: Oskari Lemmela +--- + drivers/hwmon/Kconfig | 13 +++++++++++++ + drivers/hwmon/Makefile | 2 ++ + 2 files changed, 15 insertions(+) + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index c4578e8f34bb..9bcd1df93565 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1541,6 +1541,19 @@ config SENSORS_RASPBERRYPI_HWMON + This driver can also be built as a module. If so, the module + will be called raspberrypi-hwmon. + ++config SENSORS_MIKROTIK_POE ++ tristate "Mikrotik POE driver" ++ select CRC8 ++ depends on SPI ++ help ++ If you say yes here you get support for Mikrotik POE ++ ++config SENSORS_MIKROTIK_POEPORT ++ tristate "Mikrotik POE port driver" ++ depends on SENSORS_MIKROTIK_POE ++ help ++ If you say yes here you get support for Mikrotik POE ++ + config SENSORS_SL28CPLD + tristate "Kontron sl28cpld hardware monitoring driver" + depends on MFD_SL28CPLD || COMPILE_TEST +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 162940270661..2778b2562ee1 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -162,6 +162,8 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o + obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o + obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o + obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o ++obj-$(CONFIG_SENSORS_MIKROTIK_POE) += rbpoe.o ++obj-$(CONFIG_SENSORS_MIKROTIK_POEPORT) += rbpoeport.o + obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o + obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o + obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o +-- +2.25.1 +