From: "Andreas Böhler" <dev@aboehler.at>
To: unlisted-recipients:; (no To-header on input)
Cc: dev@aboehler.at, Robert Marko <robert.marko@sartura.hr>,
Luka Perkov <luka.perkov@sartura.hr>,
Jean Delvare <jdelvare@suse.com>,
Guenter Roeck <linux@roeck-us.net>,
Rob Herring <robh+dt@kernel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v2] hwmon: tps23861: add support for initializing the chip
Date: Thu, 25 Aug 2022 16:10:42 +0200 [thread overview]
Message-ID: <20220825141043.75354-1-dev@aboehler.at> (raw)
The tps23861 driver does not initialize the chip and relies on it being
in auto-mode by default. On some devices, these controllers default to
OFF-Mode and hence cannot be used at all.
This brings minimal support for initializing the controller in a user-
defined mode.
Tested on a TP-Link TL-SG2452P with 12x TI TPS23861 controllers.
Signed-off-by: Andreas Böhler <dev@aboehler.at>
---
.../bindings/hwmon/ti,tps23861.yaml | 76 +++++++++++++++++
drivers/hwmon/tps23861.c | 81 +++++++++++++++++++
2 files changed, 157 insertions(+)
diff --git a/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml b/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml
index 3bc8e73dfbf0..ed3a703478fb 100644
--- a/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml
+++ b/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml
@@ -35,6 +35,50 @@ required:
- compatible
- reg
+patternProperties:
+ "^port@([0-3])$":
+ type: object
+ description: Represents ports of the device and their specific configuration.
+
+ properties:
+ reg:
+ description: The port number
+ items:
+ minimum: 0
+ maximum: 3
+
+ mode:
+ description: The operating mode the device should be initialized with
+ items:
+ - enum:
+ - auto
+ - semiauto
+ - manual
+ - off
+
+ enable:
+ description: Whether the port should be enabled
+ items:
+ minimum: 0
+ maximum: 1
+
+ power:
+ description: Whether the port should be powered on
+ items:
+ minimum: 0
+ maximum: 1
+
+ poe_plus:
+ description: Whether the port should support PoE+
+ items:
+ minimum: 0
+ maximum: 1
+
+ required:
+ - reg
+
+ additionalProperties: false
+
additionalProperties: false
examples:
@@ -47,5 +91,37 @@ examples:
compatible = "ti,tps23861";
reg = <0x30>;
shunt-resistor-micro-ohms = <255000>;
+
+ port@0 {
+ reg = <0>;
+ mode = "auto";
+ enable = <1>;
+ power = <1>;
+ poe_plus = <1>;
+ };
+
+ port@1 {
+ reg = <1>;
+ mode = "semiauto";
+ enable = <1>;
+ power = <0>;
+ poe_plus = <1>;
+ };
+
+ port@2 {
+ reg = <2>;
+ mode = "manual";
+ enable = <0>;
+ power = <0>;
+ poe_plus = <0>;
+ };
+
+ port@3 {
+ reg = <3>;
+ mode = "off";
+ enable = <0>;
+ power = <0>;
+ poe_plus = <1>;
+ };
};
};
diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c
index 42762e87b014..27bf8716cf12 100644
--- a/drivers/hwmon/tps23861.c
+++ b/drivers/hwmon/tps23861.c
@@ -85,6 +85,8 @@
#define PORT_DETECT_CAPACITANCE_INVALID_DELTA 11
#define PORT_DETECT_CAPACITANCE_OUT_OF_RANGE 12
#define POE_PLUS 0x40
+#define POE_PLUS_MASK(_port) \
+ GENMASK(_port + 4, _port + 4)
#define OPERATING_MODE 0x12
#define OPERATING_MODE_OFF 0
#define OPERATING_MODE_MANUAL 1
@@ -94,9 +96,22 @@
#define OPERATING_MODE_PORT_2_MASK GENMASK(3, 2)
#define OPERATING_MODE_PORT_3_MASK GENMASK(5, 4)
#define OPERATING_MODE_PORT_4_MASK GENMASK(7, 6)
+#define OPERATING_MODE_PORT(_mode, _port) \
+ (_mode << (_port * 2))
+#define DISCONNECT_ENABLE 0x13
+#define DISCONNECT_ENABLE_MASK(_port) \
+ GENMASK(_port, _port)
+#define DISCONNECT_MASK(_port) \
+ (GENMASK(_port, _port) | GENMASK(_port + 4, _port + 4))
+
+#define DETECT_CLASS_ENABLE 0x14
#define DETECT_CLASS_RESTART 0x18
#define POWER_ENABLE 0x19
+#define POWER_ENABLE_ON_MASK(_port) \
+ GENMASK(_port, _port)
+#define POWER_ENABLE_OFF_MASK(_port) \
+ GENMASK(_port + 4, _port + 4)
#define TPS23861_NUM_PORTS 4
#define TPS23861_GENERAL_MASK_1 0x17
@@ -548,7 +563,16 @@ static int tps23861_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct tps23861_data *data;
struct device *hwmon_dev;
+ struct device_node *child;
u32 shunt_resistor;
+ u32 reg;
+ u32 temp;
+ const char *mode;
+ unsigned int poe_plusval;
+ unsigned int mode_val;
+ unsigned int power_val;
+ unsigned int enable_val;
+ unsigned int disconnect_enable_val;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -577,6 +601,63 @@ static int tps23861_probe(struct i2c_client *client)
TPS23861_GENERAL_MASK_1,
TPS23861_CURRENT_SHUNT_MASK);
+ regmap_read(data->regmap, POE_PLUS, &poe_plusval);
+ regmap_read(data->regmap, POWER_ENABLE, &power_val);
+ regmap_read(data->regmap, OPERATING_MODE, &mode_val);
+ regmap_read(data->regmap, DETECT_CLASS_ENABLE, &enable_val);
+ regmap_read(data->regmap, DISCONNECT_ENABLE, &disconnect_enable_val);
+
+ for_each_child_of_node(dev->of_node, child) {
+ if (of_property_read_u32(child, "reg", ®))
+ continue;
+
+ if (reg > (TPS23861_NUM_PORTS - 1) || reg < 0)
+ continue;
+
+ if (!of_property_read_string(child, "mode", &mode)) {
+ if (!strncmp(mode, "manual", 6)) {
+ mode_val &= ~OPERATING_MODE_PORT(OPERATING_MODE_AUTO, reg);
+ mode_val |= OPERATING_MODE_PORT(OPERATING_MODE_MANUAL, reg);
+ } else if (!strncmp(mode, "semiauto", 8)) {
+ mode_val &= ~OPERATING_MODE_PORT(OPERATING_MODE_AUTO, reg);
+ mode_val |= OPERATING_MODE_PORT(OPERATING_MODE_SEMI, reg);
+ } else if (!strncmp(mode, "auto", 4))
+ mode_val |= OPERATING_MODE_PORT(OPERATING_MODE_AUTO, reg);
+ else
+ mode_val &= ~OPERATING_MODE_PORT(OPERATING_MODE_AUTO, reg);
+ }
+
+ if (!of_property_read_u32(child, "enable", &temp)) {
+ if (temp) {
+ enable_val |= DISCONNECT_MASK(reg);
+ disconnect_enable_val |= DISCONNECT_ENABLE_MASK(reg);
+ } else {
+ enable_val &= ~DISCONNECT_MASK(reg);
+ disconnect_enable_val &= ~DISCONNECT_ENABLE_MASK(reg);
+ }
+ }
+
+ if (!of_property_read_u32(child, "power", &temp)) {
+ if (temp)
+ power_val |= POWER_ENABLE_ON_MASK(reg);
+ else
+ power_val |= POWER_ENABLE_OFF_MASK(reg);
+ }
+
+ if (!of_property_read_u32(child, "poe_plus", &temp)) {
+ if (temp)
+ poe_plusval |= POE_PLUS_MASK(reg);
+ else
+ poe_plusval &= ~POE_PLUS_MASK(reg);
+ }
+ }
+
+ regmap_write(data->regmap, POE_PLUS, poe_plusval);
+ regmap_write(data->regmap, POWER_ENABLE, power_val);
+ regmap_write(data->regmap, OPERATING_MODE, mode_val);
+ regmap_write(data->regmap, DETECT_CLASS_ENABLE, enable_val);
+ regmap_write(data->regmap, DISCONNECT_ENABLE, disconnect_enable_val);
+
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data, &tps23861_chip_info,
NULL);
--
2.37.2
next reply other threads:[~2022-08-25 14:11 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-25 14:10 Andreas Böhler [this message]
2022-08-25 14:17 ` [PATCH v2] hwmon: tps23861: add support for initializing the chip Krzysztof Kozlowski
2022-08-25 15:00 ` Guenter Roeck
2022-08-25 18:51 ` Rob Herring
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220825141043.75354-1-dev@aboehler.at \
--to=dev@aboehler.at \
--cc=devicetree@vger.kernel.org \
--cc=jdelvare@suse.com \
--cc=krzysztof.kozlowski+dt@linaro.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=luka.perkov@sartura.hr \
--cc=robert.marko@sartura.hr \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).