Re: [PATCH v4 2/7] hwmon: pmbus: adm1266: Add Block process call

From: Guenter Roeck
Date: Wed Jun 24 2020 - 17:28:23 EST


On Tue, Jun 23, 2020 at 08:36:54PM +0300, alexandru.tachici@xxxxxxxxxx wrote:
> From: Alexandru Tachici <alexandru.tachici@xxxxxxxxxx>
>
> PmBus devices support Block Write-Block Read Process
> Call described in SMBus specification v 2.0 with the
> exception that Block writes and reads are permitted to
> have up 255 data bytes instead of max 32 bytes (SMBus).
>
> This patch adds Block WR process call support for ADM1266.
>
> Signed-off-by: Alexandru Tachici <alexandru.tachici@xxxxxxxxxx>
> ---
> drivers/hwmon/pmbus/Kconfig | 1 +
> drivers/hwmon/pmbus/adm1266.c | 79 +++++++++++++++++++++++++++++++++++
> 2 files changed, 80 insertions(+)
>
> diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
> index 6949483aa732..dc6971a7c49e 100644
> --- a/drivers/hwmon/pmbus/Kconfig
> +++ b/drivers/hwmon/pmbus/Kconfig
> @@ -28,6 +28,7 @@ config SENSORS_PMBUS
>
> config SENSORS_ADM1266
> tristate "Analog Devices ADM1266 Sequencer"
> + select CRC8
> help
> If you say yes here you get hardware monitoring support for Analog
> Devices ADM1266 Cascadable Super Sequencer.
> diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
> index a7ef048a9a5c..381d89a8569f 100644
> --- a/drivers/hwmon/pmbus/adm1266.c
> +++ b/drivers/hwmon/pmbus/adm1266.c
> @@ -6,6 +6,7 @@
> * Copyright 2020 Analog Devices Inc.
> */
>
> +#include <linux/crc8.h>
> #include <linux/i2c.h>
> #include <linux/init.h>
> #include <linux/kernel.h>
> @@ -14,6 +15,82 @@
>
> #include "pmbus.h"
>
> +#define ADM1266_PMBUS_BLOCK_MAX 255
> +
> +DECLARE_CRC8_TABLE(pmbus_crc_table);
> +
> +/* Different from Block Read as it sends data and waits for the slave to

/*
* Proper multi-line comment
*/

> + * return a value dependent on that data. The protocol is simply a Write Block
> + * followed by a Read Block without the Read-Block command field and the
> + * Write-Block STOP bit.
> + */

static

> +int pmbus_block_xfer(struct i2c_client *client, u8 cmd, u8 w_len,
> + u8 *data_w, u8 *data_r)
> +{
> + u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 2];
> + struct i2c_msg msgs[2] = {
> + {
> + .addr = client->addr,
> + .flags = 0,
> + .buf = write_buf,
> + .len = w_len + 2,
> + },
> + {
> + .addr = client->addr,
> + .flags = I2C_M_RD,
> + .len = ADM1266_PMBUS_BLOCK_MAX + 2,
> + }
> + };
> + u8 addr = 0;
> + u8 crc = 0;

Unnecessary initialization for both variables

> + int ret;
> +
> + msgs[0].buf[0] = cmd;
> + msgs[0].buf[1] = w_len;
> + memcpy(&msgs[0].buf[2], data_w, w_len);
> +
> + msgs[0].buf = i2c_get_dma_safe_msg_buf(&msgs[0], 1);
> + if (!msgs[0].buf)
> + return -ENOMEM;
> +
> + msgs[1].buf = i2c_get_dma_safe_msg_buf(&msgs[1], 1);
> + if (!msgs[1].buf) {
> + i2c_put_dma_safe_msg_buf(msgs[0].buf, &msgs[0], false);
> + return -ENOMEM;
> + }

AFAICS i2c_get_dma_safe_msg_buf() is supposed to be used by i2c bus drivers,
not by device drivers. If this is needed for the target architecture,
it should be implemented in the bus driver, not here.

> +
> + ret = i2c_transfer(client->adapter, msgs, 2);
> + if (ret != 2) {
> + ret = -EPROTO;

Should retain error if ret < 0, and only return EPROTO if the return value
is 0 or 1.

> + goto cleanup;
> + }
> +
> + if (client->flags & I2C_CLIENT_PEC) {
> + addr = i2c_8bit_addr_from_msg(&msgs[0]);
> + crc = crc8(pmbus_crc_table, &addr, 1, crc);
> + crc = crc8(pmbus_crc_table, msgs[0].buf, msgs[0].len, crc);
> +
> + addr = i2c_8bit_addr_from_msg(&msgs[1]);
> + crc = crc8(pmbus_crc_table, &addr, 1, crc);
> + crc = crc8(pmbus_crc_table, msgs[1].buf, msgs[1].buf[0] + 1,
> + crc);
> +
> + if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) {
> + ret = -EBADMSG;
> + goto cleanup;
> + }
> + }
> +
> + memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]);
> + ret = msgs[1].buf[0];
> +
> +cleanup:
> + i2c_put_dma_safe_msg_buf(msgs[0].buf, &msgs[0], true);
> + i2c_put_dma_safe_msg_buf(msgs[1].buf, &msgs[1], true);
> +
> + return ret;
> +}
> +
> static int adm1266_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> {
> @@ -24,6 +101,8 @@ static int adm1266_probe(struct i2c_client *client,
> info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
> GFP_KERNEL);
>
> + crc8_populate_msb(pmbus_crc_table, 0x7);
> +
> info->pages = 17;
> info->format[PSC_VOLTAGE_OUT] = linear;
> funcs = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;