Re: [PATCH 1/3] hwmon: (pmbus) Add driver for Delta DPS-920AB PSU

From: Robert Marko
Date: Thu May 27 2021 - 15:43:48 EST


On Thu, May 27, 2021 at 9:27 PM Guenter Roeck <linux@xxxxxxxxxxxx> wrote:
>
> On Thu, May 27, 2021 at 09:14:03PM +0200, Robert Marko wrote:
> > On Thu, May 27, 2021 at 6:37 PM Guenter Roeck <linux@xxxxxxxxxxxx> wrote:
> > >
> > > On 5/27/21 7:58 AM, Robert Marko wrote:
> > > [ ... ]
> > >
> > > >>>>>> I tried applying the block support for mv64xx as well:
> > > >>>>>> https://patchwork.ozlabs.org/project/linux-i2c/patch/20200118115820.9080-1-fuga@xxxxxxxxxxxxxx/
> > > >>>>
> > > >>>> That patch would be needed, but it looks buggy to me. This chunk:
> > > >>>>
> > > >>>> + drv_data->effective_length = data+1;
> > > >>>> + drv_data->bytes_left = data+1;
> > > >>>> + drv_data->msg->len = data+1;
> > > >>>>
> > > >>>> should be:
> > > >>>>
> > > >>>> + drv_data->effective_length = data+1;
> > > >>>> + drv_data->bytes_left = data;
> > > >>>> + drv_data->msg->len = data+1;
> > > >>>>
> > > >>>> It should also make sure that 'data' is not larger than I2C_SMBUS_BLOCK_MAX,
> > > >>>> and bail out if it isn't.
> > > >>>
> > > >>> Yeah, I did not check the contents, I just saw 2 reviews and tested it
> > > >>> since it can't hurt.
> > > >>
> > > >> That patch doesn't work at all. Make the above change, and also change
> > > >> the type of effective_length from u32 to int, and try again.
> > > >
> > > > I was just looking and it, and doing the changes you recommended make
> > > > no difference at all.
> > > >
> > >
> > > Is the i2c controller compatible with marvell,mv78230-i2c ?
> > > The block transfers would not work in that case. Let me know
> > > and I'll send you a patch that might fix it.
> >
> > Yes, the CPU is Armada 7040 and I can see that compatible is
> > marvell,mv78230-i2c indeed.
> >
> > It would be great if you have the patch,
>
> See below.

I can confirm that this does indeed enable block reads and
i2c_smbus_read_block_data()
works now.

PMBUS_MFR_ID and PMBUS_MFR_MODEL are indeed populated.

Regards,
Robert

>
> Guenter
>
> ---
> From 41f6113560e3082293cef6e8f2013e70ee8f54db Mon Sep 17 00:00:00 2001
> From: Federico Fuga <fuga@xxxxxxxxxxxxxx>
> Date: Sat, 18 Jan 2020 12:58:20 +0100
> Subject: [PATCH] i2c: mv64xxx: Implement I2C_M_RECV_LEN and
> I2C_FUNC_SMBUS_READ_BLOCK_DATA
>
> The i2c_mv64xxx driver doesn't implement the I2C_M_REC_LEN function
> essential to allow blocks with variable length to be read from an i2c
> slave.
> This is needed to implement the SMBus Read Block Data function.
>
> This patch implements the function by changing the bytes_left and
> msg len on the fly if the flag is specified.
>
> It has been successfully tested on Allwinner A33 with a special
> i2c chip that returns variable length blocks on reading.
>
> Signed-off-by: Federico Fuga <fuga@xxxxxxxxxxxxxx>
> Acked-by: Gregory CLEMENT <gregory.clement@xxxxxxxxxxx>
> Link: https://lore.kernel.org/r/20200118115820.9080-1-fuga@xxxxxxxxxxxxxx
> [groeck: Various fixes]
> Signed-off-by: Guenter Roeck <linux@xxxxxxxxxxxx>
> ---
> drivers/i2c/busses/i2c-mv64xxx.c | 75 ++++++++++++++++++++++++++------
> 1 file changed, 61 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
> index 5c8e94b6cdb5..9dda90359966 100644
> --- a/drivers/i2c/busses/i2c-mv64xxx.c
> +++ b/drivers/i2c/busses/i2c-mv64xxx.c
> @@ -341,7 +341,17 @@ static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
> {
> drv_data->msg = drv_data->msgs;
> drv_data->byte_posn = 0;
> - drv_data->bytes_left = drv_data->msg->len;
> +
> + /*
> + * If we should retrieve the length from the buffer, make sure
> + * to read enough bytes to avoid sending the STOP bit after
> + * the read if the first byte
> + */
> + if (drv_data->msg->flags & I2C_M_RECV_LEN)
> + drv_data->bytes_left = 3;
> + else
> + drv_data->bytes_left = drv_data->msg->len;
> +
> drv_data->aborting = 0;
> drv_data->rc = 0;
>
> @@ -350,6 +360,47 @@ static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
> drv_data->reg_base + drv_data->reg_offsets.control);
> }
>
> +static void
> +mv64xxx_i2c_do_send_stop(struct mv64xxx_i2c_data *drv_data)
> +{
> + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
> + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
> + drv_data->reg_base + drv_data->reg_offsets.control);
> + drv_data->block = 0;
> + if (drv_data->errata_delay)
> + udelay(5);
> +
> + wake_up(&drv_data->waitq);
> +}
> +
> +static void
> +mv64xxx_i2c_do_read_data(struct mv64xxx_i2c_data *drv_data)
> +{
> + u8 data;
> +
> + data = readl(drv_data->reg_base + drv_data->reg_offsets.data);
> + drv_data->msg->buf[drv_data->byte_posn++] = data;
> +
> + if (drv_data->msg->flags & I2C_M_RECV_LEN) {
> + if (!data || data > I2C_SMBUS_BLOCK_MAX) {
> + /*
> + * FIXME
> + * Abort and report error. Needs to be
> + * verified/tested on real hardware.
> + */
> + drv_data->rc = -EPROTO;
> + mv64xxx_i2c_do_send_stop(drv_data);
> + return;
> + }
> + drv_data->msg->flags &= ~I2C_M_RECV_LEN;
> + drv_data->bytes_left = data;
> + drv_data->msg->len = data + 1;
> + }
> +
> + writel(drv_data->cntl_bits,
> + drv_data->reg_base + drv_data->reg_offsets.control);
> +}
> +
> static void
> mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
> {
> @@ -400,23 +451,13 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
> break;
>
> case MV64XXX_I2C_ACTION_RCV_DATA:
> - drv_data->msg->buf[drv_data->byte_posn++] =
> - readl(drv_data->reg_base + drv_data->reg_offsets.data);
> - writel(drv_data->cntl_bits,
> - drv_data->reg_base + drv_data->reg_offsets.control);
> + mv64xxx_i2c_do_read_data(drv_data);
> break;
>
> case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
> drv_data->msg->buf[drv_data->byte_posn++] =
> readl(drv_data->reg_base + drv_data->reg_offsets.data);
> - drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
> - writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
> - drv_data->reg_base + drv_data->reg_offsets.control);
> - drv_data->block = 0;
> - if (drv_data->errata_delay)
> - udelay(5);
> -
> - wake_up(&drv_data->waitq);
> + mv64xxx_i2c_do_send_stop(drv_data);
> break;
>
> case MV64XXX_I2C_ACTION_INVALID:
> @@ -680,6 +721,10 @@ mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data)
> if (!drv_data->offload_enabled)
> return false;
>
> + /* Offload not supported for block data transfers */
> + if (msgs[0].flags & I2C_M_RECV_LEN)
> + return false;
> +
> /*
> * We can offload a transaction consisting of a single
> * message, as long as the message has a length between 1 and
> @@ -697,6 +742,7 @@ mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data)
> mv64xxx_i2c_valid_offload_sz(msgs) &&
> mv64xxx_i2c_valid_offload_sz(msgs + 1) &&
> !(msgs[0].flags & I2C_M_RD) &&
> + !(msgs[1].flags & I2C_M_RECV_LEN) &&
> msgs[1].flags & I2C_M_RD)
> return true;
>
> @@ -713,7 +759,8 @@ mv64xxx_i2c_can_offload(struct mv64xxx_i2c_data *drv_data)
> static u32
> mv64xxx_i2c_functionality(struct i2c_adapter *adap)
> {
> - return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
> + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
> + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_EMUL;
> }
>
> static int
> --
> 2.25.1
>


--
Robert Marko
Staff Embedded Linux Engineer
Sartura Ltd.
Lendavska ulica 16a
10000 Zagreb, Croatia
Email: robert.marko@xxxxxxxxxx
Web: www.sartura.hr