mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Piotr Kubik <piotr.kubik@adtran.com>
To: Kory Maincent <kory.maincent@bootlin.com>
Cc: Oleksij Rempel <o.rempel@pengutronix.de>,
	Andrew Lunn <andrew+netdev@lunn.ch>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH net-next v3 2/2] net: pse-pd: Add Si3474 PSE controller driver
Date: Wed, 21 May 2025 08:04:23 +0000	[thread overview]
Message-ID: <e036f7e2-5e5d-40bc-b22c-6dbd6a34eb15@adtran.com> (raw)
In-Reply-To: <20250519115439.35382771@kmaincent-XPS-13-7390>

On 5/19/25 11:54, Kory Maincent wrote:
> On Fri, 16 May 2025 13:07:18 +0000
> Piotr Kubik <piotr.kubik@adtran.com> wrote:
> 
>> From: Piotr Kubik <piotr.kubik@adtran.com>
>>
>> Add a driver for the Skyworks Si3474 I2C Power Sourcing Equipment
>> controller.
>>
>> Based on the TPS23881 driver code.
>>
>> Driver supports basic features of Si3474 IC:
>> - get port status,
>> - get port power,
>> - get port voltage,
>> - enable/disable port power.
>>
>> Only 4p configurations are supported at this moment.
> 
> By curiosity, I suppose your hardware have only PoE4 PIs. Could you support and
> test 2p configuration by only configuring 2 of the 4 pairs on one PI?
> 
> Maybe it could be done on a second stage if you prefer.
> 

Yes, exactly. My PSE is hardware 4p type. Some tweaks needs to be done to test/support 2p PSE.
And, yes, I'd prefer to do it in a second stage as a feature.

>>
>> Signed-off-by: Piotr Kubik <piotr.kubik@adtran.com>
> 
> ...
> 
>> +	is_enabled = ((ret & (0x03 << (2 * (chan0 % 4)))) |
>> +		      (ret & (0x03 << (2 * (chan1 % 4))))) != 0;
> 
> There are precedence in the operators. I don't think you need that much of
> parenthesis.
> This should do the work:
> is_enabled = (ret & 0x03 << chan0 % 4 * 2) |
>              (ret & 0x03 << chan1 % 4 * 2) != 0;

Indeed, I left if for readability of what is going on, but your version looks also readable. 
But I'd keep the most surrounding parenthesis as '!=' has precedence over '|' 

is_enabled = ((ret & 0x03 << chan0 % 4 * 2) |
              (ret & 0x03 << chan1 % 4 * 2)) != 0;
> 
> Also I saw that this kind of calculation is made several times. Maybe you could
> add a helper with documentation like I did:
> https://elixir.bootlin.com/linux/v6.14.7/source/drivers/net/pse-pd/tps23881.c#L79 

Sure, I will. 

>> +/* Parse pse-pis subnode into chan array of si3474_priv */
>> +static int si3474_get_of_channels(struct si3474_priv *priv)
>> +{
>> +	struct device_node *pse_node;
>> +	struct pse_pi *pi;
>> +	u32 pi_no, chan_id;
>> +	s8 pairset_cnt;
>> +	s32 ret = 0;
>> +
>> +	pse_node = of_get_child_by_name(priv->np, "pse-pis");
>> +	if (!pse_node) {
>> +		dev_warn(&priv->client[0]->dev,
>> +			 "Unable to parse DT PSE power interface matrix, no
>> pse-pis node\n");
>> +		return -EINVAL;
>> +	}
> 
> You should not parse the pse-pis node and subnodes, it is already done before
> the setup_pi_matrix ops call in the core framework.
> https://elixir.bootlin.com/linux/v6.14.7/source/drivers/net/pse-pd/pse_core.c#L131
> 
> You should rather use directly the pcdev->pi[x] table. You have to match the
> the phandle save in pcdev->pi[x].pairset[0/1].np to your channel device node
> and set up the hardware matrix accordingly.

OK, I didn't notice that, will try. 

> 
> That's good to have another development on PSE, this shows me that documentation
> are missing or not enough in PSE core like on this ops. I will update it when I
> have time.
> 
>> +
>> +	for_each_child_of_node_scoped(pse_node, node) {
>> +		if (!of_node_name_eq(node, "pse-pi"))
>> +			continue;
>> +
>> +		ret = of_property_read_u32(node, "reg", &pi_no);
>> +		if (ret) {
>> +			dev_err(&priv->client[0]->dev,
>> +				"Failed to read pse-pi reg property\n");
>> +			goto out;
>> +		}
>> +		if (pi_no >= SI3474_MAX_CHANS) {
>> +			dev_err(&priv->client[0]->dev,
>> +				"Invalid power interface number %u\n",
>> pi_no);
>> +			ret = -EINVAL;
>> +			goto out;
>> +		}
>> +
> 
> ...
> 
>> +static int si3474_pi_enable(struct pse_controller_dev *pcdev, int id)
>> +{
>> +	struct si3474_priv *priv = to_si3474_priv(pcdev);
>> +	struct i2c_client *client;
>> +	u8 chan0, chan1;
>> +	u8 val = 0;
>> +	s32 ret;
>> +
>> +	if (id >= SI3474_MAX_CHANS)
>> +		return -ERANGE;
>> +
>> +	chan0 = priv->pi[id].chan[0];
>> +	chan1 = priv->pi[id].chan[1];
>> +
>> +	if (chan0 < 4)
>> +		client = priv->client[0];
>> +	else
>> +		client = priv->client[1];
>> +
>> +	/* Release pi from shutdown */
>> +	ret = i2c_smbus_read_byte_data(client, PORT_MODE_REG);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	val = (u8)ret;
>> +	val |= (0x03 << (2 * (chan0 % 4)));
>> +	val |= (0x03 << (2 * (chan1 % 4)));
> 
> Same calculation as before, use a helper as said before.
> 
>> +
>> +	ret = i2c_smbus_write_byte_data(client, PORT_MODE_REG, val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* Give time for transition to complete */
>> +	ssleep(1);
> 
> 1s sleep?! It is a lot. Why do you need this? Does it comes from the datasheet?
> 

This comes from my experience. I didn't find it in a datasheet.
I agree this seems a lot, but for 500ms sometimes ports were not powered up. 
I think I'll give a try to another register and instead PB_POWER_ENABLE 
I will try to use PB_RESET in combination with PORT_MODE as this seems promising.

btw. Regarding power enable/disable, I think you may have same issue in tps23881 
as I had here as tps looks very similar to si3474.
For Si3474 POWER_STATUS register cannot be used as an admin state register as it
holds actual power interface status (powered/not powered) instead of its
administrative state (enabled/disabled). 
Ethtool in this approach was showing for both Admin state and Detection status 
always the same state - actual status.
PB_POWER_ENABLE register cannot be used for this purpose as well as it is a write-only register.
That's why I used PORT_MODE register, it acts like an admin state holder in my implementation.

>> +
>> +	/* Trigger pi to power up */
>> +	val = (BIT(chan0 % 4) | BIT(chan1 % 4));
>> +	ret = i2c_smbus_write_byte_data(client, PB_POWER_ENABLE_REG, val);
>> +
>> +	return 0;
>> +}
>> +
>> +static int si3474_pi_disable(struct pse_controller_dev *pcdev, int id)
>> +{
>> +	struct si3474_priv *priv = to_si3474_priv(pcdev);
>> +	struct i2c_client *client;
>> +	u8 chan0, chan1;
>> +	u8 val = 0;
>> +	s32 ret;
>> +
>> +	if (id >= SI3474_MAX_CHANS)
>> +		return -ERANGE;
>> +
>> +	chan0 = priv->pi[id].chan[0];
>> +	chan1 = priv->pi[id].chan[1];
>> +
>> +	if (chan0 < 4)
>> +		client = priv->client[0];
>> +	else
>> +		client = priv->client[1];
>> +
>> +	/* Trigger pi to power down */
>> +	val = (BIT((chan0 % 4) + 4) | BIT((chan1 % 4) + 4));
> 
> This calculation is also used several times. Please use a helper with
> documentation.
> 
>> +	ret = i2c_smbus_write_byte_data(client, PB_POWER_ENABLE_REG, val);
>> +
>> +	/* Shutdown pi */
>> +	ret = i2c_smbus_read_byte_data(client, PORT_MODE_REG);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	val = (u8)ret;
>> +	val &= ~(0x03 << (2 * (chan0 % 4)));
>> +	val &= ~(0x03 << (2 * (chan1 % 4)));
> 
> Use a helper.
> 
>> +
>> +	ret = i2c_smbus_write_byte_data(client, PORT_MODE_REG, val);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> +}
>> +
>> +static int si3474_pi_get_chan_current(struct si3474_priv *priv, u8 chan)
>> +{
>> +	struct i2c_client *client;
>> +	s32 ret;
>> +	u8 reg;
>> +	u64 tmp_64;
>> +
>> +	if (chan < 4)
>> +		client = priv->client[0];
>> +	else
>> +		client = priv->client[1];
>> +
>> +	/* Registers 0x30 to 0x3d */
>> +	reg = PORT1_CURRENT_LSB_REG + (chan % 4) * 4;
> 
> Idem
> 
>> +
>> +	ret = i2c_smbus_read_word_data(client, reg);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	tmp_64 = ret * SI3474_NA_STEP;
>> +
>> +	/* uA = nA / 1000 */
>> +	tmp_64 = DIV_ROUND_CLOSEST_ULL(tmp_64, 1000);
>> +	return (int)tmp_64;
>> +}
>> +
>> +static int si3474_pi_get_chan_voltage(struct si3474_priv *priv, u8 chan)
>> +{
>> +	struct i2c_client *client;
>> +	s32 ret;
>> +	u8 reg;
>> +	u32 val;
>> +
>> +	if (chan < 4)
>> +		client = priv->client[0];
>> +	else
>> +		client = priv->client[1];
>> +
>> +	/* Registers 0x32 to 0x3f */
>> +	reg = PORT1_VOLTAGE_LSB_REG + (chan % 4) * 4;
> 
> Idem
> 
>> +
>> +	ret = i2c_smbus_read_word_data(client, reg);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	val = ret * SI3474_UV_STEP;
>> +
>> +	return (int)val;
>> +}
> 
> Regards,

Thanks Kory!
/Piotr


  reply	other threads:[~2025-05-21  8:04 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-16 13:06 [PATCH net-next v3 0/2] " Piotr Kubik
2025-05-16 13:07 ` [PATCH net-next v3 1/2] dt-bindings: net: pse-pd: Add bindings for Si3474 PSE controller Piotr Kubik
2025-05-16 19:46   ` Krzysztof Kozlowski
2025-05-19  8:46   ` Kory Maincent
2025-05-16 13:07 ` [PATCH net-next v3 2/2] net: pse-pd: Add Si3474 PSE controller driver Piotr Kubik
2025-05-16 21:38   ` ALOK TIWARI
2025-05-21  8:04     ` Piotr Kubik
2025-05-19  9:54   ` Kory Maincent
2025-05-21  8:04     ` Piotr Kubik [this message]
2025-05-21 21:49       ` Kory Maincent
2025-05-22  9:29   ` Oleksij Rempel
2025-06-05 17:04     ` [EXTERNAL]Re: " Piotr Kubik

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=e036f7e2-5e5d-40bc-b22c-6dbd6a34eb15@adtran.com \
    --to=piotr.kubik@adtran.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=conor+dt@kernel.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=edumazet@google.com \
    --cc=kory.maincent@bootlin.com \
    --cc=krzk+dt@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=o.rempel@pengutronix.de \
    --cc=pabeni@redhat.com \
    --cc=robh@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

all inboxes | Powered by JetHome®