lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:   Fri, 16 Oct 2020 14:41:37 -0700
From:   Guenter Roeck <linux@...ck-us.net>
To:     "xiao.mx.ma" <734056705@...com>
Cc:     Jean Delvare <jdelvare@...e.com>, linux-hwmon@...r.kernel.org,
        linux-kernel@...r.kernel.org, xiao.mx.ma@...taww.com,
        jiajia.feng@...taww.com
Subject: Re: [PATCH] hwmon:Driver for Delta power supplies

On Tue, Oct 13, 2020 at 06:54:55AM +0100, xiao.mx.ma wrote:
> From: Delta <xiao.mx.ma@...taww.com>
> 
> The <drivers/hwmon/pmbus/delta.c> provides a driver for Delta's modules.
> Currently supports Q54SN108A2 series and other series will continue to be
> added in the future.
> 
> Signed-off-by: Delta <xiao.mx.ma@...taww.com>

The submitter has to be a person, not a company name.

I don't know how this happened, but the patch is not visible on patchwork.

I am not happy that this is submitted as new driver. It should be (at least)
v5. Actually, looking into my e-mail archive, it is really v7.
Each version is pretty much completely different and suggests something
else that is unacceptable. More on that below.

Please version your patches in the future, and provide change logs.
Also please check why your patches don't make it into patchwork.

Guenter

> ---
>  Documentation/hwmon/delta.rst |  77 ++++++
>  Documentation/hwmon/index.rst |   1 +
>  drivers/hwmon/pmbus/Kconfig   |   9 +
>  drivers/hwmon/pmbus/Makefile  |   1 +
>  drivers/hwmon/pmbus/delta.c   | 448 ++++++++++++++++++++++++++++++++++
>  5 files changed, 536 insertions(+)
>  create mode 100644 Documentation/hwmon/delta.rst
>  create mode 100755 drivers/hwmon/pmbus/delta.c
> 
> diff --git a/Documentation/hwmon/delta.rst b/Documentation/hwmon/delta.rst
> new file mode 100644
> index 000000000000..daccb31ca222
> --- /dev/null
> +++ b/Documentation/hwmon/delta.rst
> @@ -0,0 +1,77 @@
> +Kernel driver delta
> +=====================
> +
> +Supported chips:
> +
> +  * DELTA Q54SJ108A2NCAH, Q54SJ108A2NCDH, Q54SJ108A2NCPG, Q54SJ108A2NCPH
> +
> +    Prefix: 'Q54SJ108A2'
> +
> +    Addresses scanned: -
> +
> +    Datasheet: https://filecenter.delta-china.com.cn/products/download/01/0102/datasheet/DS_Q54SJ108A2.pdf
> +
> +Authors:
> +    Delta <xiao.mx.ma@...taww.com>
> +
> +
> +Description
> +-----------
> +
> +This driver implements support for DELTA Q54SJ108A2NCAH, Q54SJ108A2NCDH, 
> +Q54SJ108A2NCPG, and Q54SJ108A2NCPH 1/4 Brick DC/DC Regulated Power Module 
> +with PMBus support.
> +
> +The driver is a client driver to the core PMBus driver.
> +Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
> +
> +
> +Usage Notes
> +-----------
> +
> +This driver does not auto-detect devices. You will have to instantiate the
> +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
> +details.
> +
> +
> +Sysfs entries
> +-------------
> +
> +===================== ===== ==================================================
> +curr1_alarm           RO    Output current alarm
> +curr1_input           RO    Output current
> +curr1_label           RO    'iout1'
> +in1_alarm             RO    Input voltage alarm
> +in1_input             RO    Input voltage
> +in1_label             RO    'vin'
> +in2_alarm             RO    Output voltage alarm
> +in2_input             RO    Output voltage
> +in2_label             RO    'vout1'
> +temp1_alarm           RO    Temperature alarm
> +temp1_input           RO    Chip temperature
> +operation             RW/RO Turn on or off the product according CONTROL pin.
> +			     Please see datasheet for details. Read-only if the
> +			     chip is write protected; read-write otherwise.
> +clear_fault           WO    clear alarm. Write-only if the chip is not write
> +			     protected.
> +write_protect         RW    write protect control
> +store_default         WO    store data to chip. Write-only if the chip is not
> +			     write protected.
> +vo_ovfault_response   RW/RO The response when after vout ovp. Read-only if the
> +			     chip is write protected; read-write otherwise.
> +io_ocfault_response   RW/RO The response when after iout ocp. Read-only if the
> +			     chip is write protected; read-write otherwise.
> +status_cml            RW/RO Cml status.Read-only if the chip is write protected;
> +			     read-write otherwise.
> +pmbus_revision        RO    Pmbus revision
> +mfr_id                RO    Manufacturer name
> +mfr_model             RO    Product model name
> +mfr_revision          RO    Firmware revision
> +mfr_location          RO    Place of product
> +erase_blackbox        WO    Erase a blackbox. Write-only if the chip is not
> +                            write protected.
> +read_event_num        RO    Index of blackbox
> +read_blackbox         RO    Read a blackbox
> +set_event_num         WO    Set the index of blackbox
> +flash_key             RW/RO Flash key to unlock Flash.

The non-standard attributes are not acceptable. For other PMBus drivers, we have
used debugfs to provide similar functionality. Please use the same mechanism.

The writeable attributes are not acceptable, not even as debugfs files.
Operation should be handled via the regulator subsystem, and most of the
other parameters should only be set during the manufacturing process.
I am very concerned about letting users set any of those.

The only exception might be blackbox related commands, but those are
not hwmon related and should reside in debugfs as well.

> +===================== ===== ==================================================
> diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
> index 77a1ae975037..e601367cb935 100644
> --- a/Documentation/hwmon/index.rst
> +++ b/Documentation/hwmon/index.rst
> @@ -51,6 +51,7 @@ Hardware Monitoring Kernel Drivers
>     da9052
>     da9055
>     dell-smm-hwmon
> +   delta
>     dme1737
>     drivetemp
>     ds1621
> diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
> index e35db489b76f..47e58aeec482 100644
> --- a/drivers/hwmon/pmbus/Kconfig
> +++ b/drivers/hwmon/pmbus/Kconfig
> @@ -45,6 +45,15 @@ config SENSORS_BEL_PFE
>  	  This driver can also be built as a module. If so, the module will
>  	  be called bel-pfe.
>  
> +config SENSORS_DELTA
> +	tristate "Delta Power Supplies"
> +	help
> +	  If you say yes here you get hardware monitoring support for Delta
> +	  Q54SJ108A2 series Power Supplies.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called delta.
> +
>  config SENSORS_IBM_CFFPS
>  	tristate "IBM Common Form Factor Power Supply"
>  	depends on LEDS_CLASS
> diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
> index c4b15db996ad..8957f5337002 100644
> --- a/drivers/hwmon/pmbus/Makefile
> +++ b/drivers/hwmon/pmbus/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS)		+= pmbus_core.o
>  obj-$(CONFIG_SENSORS_PMBUS)	+= pmbus.o
>  obj-$(CONFIG_SENSORS_ADM1275)	+= adm1275.o
>  obj-$(CONFIG_SENSORS_BEL_PFE)	+= bel-pfe.o
> +obj-$(CONFIG_SENSORS_DELTA)	+= delta.o
>  obj-$(CONFIG_SENSORS_IBM_CFFPS)	+= ibm-cffps.o
>  obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
>  obj-$(CONFIG_SENSORS_IR35221)	+= ir35221.o
> diff --git a/drivers/hwmon/pmbus/delta.c b/drivers/hwmon/pmbus/delta.c
> new file mode 100755
> index 000000000000..c5f6533a3c2e
> --- /dev/null
> +++ b/drivers/hwmon/pmbus/delta.c
> @@ -0,0 +1,448 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Driver for Q54SJ108A2 series Integrated, Step-Down
> + * Switching Regulators
> + *
> + * Copyright 2020 Delta LLC.
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/err.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +#include <linux/pmbus.h>
> +#include <linux/util_macros.h>
> +#include "pmbus.h"
> +
> +#define STORE_DEFAULT_ALL         0x11
> +#define ERASE_BLACKBOX_DATA       0xD1
> +#define READ_HISTORY_EVENT_NUMBER 0xD2
> +#define READ_HISTORY_EVENTS       0xE0
> +#define SET_HISTORY_EVENT_OFFSET  0xE1
> +#define PMBUS_CMD_FLASH_KEY_WRITE 0xEC
> +
> +enum chips {
> +	Q54SJ108A2
> +};
> +
> +enum delta_index {
> +	operation,
> +	clear_fault,
> +	write_protect,
> +	store_default,
> +	vo_ovfault_response,
> +	io_ocfault_response,
> +	status_cml,
> +	pmbus_revision,
> +	mfr_id,
> +	mfr_model,
> +	mfr_revision,
> +	mfr_location,
> +	erase_blackbox,
> +	read_event_num,
> +	read_blackbox,
> +	set_event_num,
> +	flash_key,
> +	num_regs,
> +};
> +
> +static const u8 delta_regs[num_regs] = {
> +	[operation] = PMBUS_OPERATION,
> +	[clear_fault] = PMBUS_CLEAR_FAULTS,
> +	[write_protect] = PMBUS_WRITE_PROTECT,
> +	[store_default] = STORE_DEFAULT_ALL,
> +	[vo_ovfault_response] = PMBUS_VOUT_OV_FAULT_RESPONSE,
> +	[io_ocfault_response] = PMBUS_IOUT_OC_FAULT_RESPONSE,
> +	[status_cml] = PMBUS_STATUS_CML,
> +	[pmbus_revision] = PMBUS_REVISION,
> +	[mfr_id] = PMBUS_MFR_ID,
> +	[mfr_model] = PMBUS_MFR_MODEL,
> +	[mfr_revision] = PMBUS_MFR_REVISION,
> +	[mfr_location] = PMBUS_MFR_LOCATION,
> +	[erase_blackbox] = ERASE_BLACKBOX_DATA,
> +	[read_blackbox] = READ_HISTORY_EVENTS,
> +	[read_event_num] = READ_HISTORY_EVENT_NUMBER,
> +	[set_event_num] = SET_HISTORY_EVENT_OFFSET,
> +	[flash_key] = PMBUS_CMD_FLASH_KEY_WRITE,
> +};
> +
> +static void char_to_char(const char *charin, char *charout, int charinsize)
> +{
> +	int i;
> +	char char_temp[2 * I2C_SMBUS_BLOCK_MAX + 1];
> +
> +	for (i = 0; i < charinsize; i++) {
> +		char_temp[i*2] = *(charin + i) & 0x0F;
> +		char_temp[i*2+1] = (*(charin + i) & 0xF0) >> 4;
> +	}
> +
> +	for (i = 0; i < (charinsize * 2); i++) {
> +		if ((char_temp[i] >= 0) && (char_temp[i] <= 9))
> +			*(charout + charinsize * 2 - 1 - i) = char_temp[i] + '0';
> +		else if ((char_temp[i] >= 0xA) && (char_temp[i] <= 0xF))
> +			*(charout + charinsize * 2 - 1 - i) = (char_temp[i] - 0xA) + 'A';
> +	}
> +}
> +
> +static ssize_t delta_byte_show(struct device *dev,
> +				 struct device_attribute *devattr,
> +				 char *buf)
> +{
> +	u8 reg;
> +	int rc;
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +	rc = i2c_smbus_read_byte_data(client, reg);
> +	if (rc < 0)
> +		return rc;
> +
> +	return snprintf(buf, PAGE_SIZE, "%02x\n", rc);
> +}
> +
> +static ssize_t delta_string_show(struct device *dev,
> +				 struct device_attribute *devattr,
> +				 char *buf)
> +{
> +	u8 reg;
> +	int rc;
> +	char *p;
> +	char data[I2C_SMBUS_BLOCK_MAX + 1];
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +	rc = i2c_smbus_read_block_data(client, reg, data);
> +	if (rc < 0)
> +		return rc;
> +
> +	/* filled with printable characters, ending with # */
> +	p = memscan(data, '#', rc);
> +	*p = '\0';
> +
> +	return snprintf(buf, PAGE_SIZE, "%s\n", data);
> +}
> +
> +static ssize_t delta_blackbox_show(struct device *dev,
> +				 struct device_attribute *devattr,
> +				 char *buf)
> +{
> +	u8 reg;
> +	int rc;
> +	char *p;
> +	char data[I2C_SMBUS_BLOCK_MAX + 1];
> +	char data_char[2 * I2C_SMBUS_BLOCK_MAX + 1];
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +	rc = i2c_smbus_read_block_data(client, reg, data);
> +	if (rc < 0)
> +		return rc;
> +
> +	char_to_char(data, data_char, rc);
> +
> +	/* filled with printable characters, ending with # */
> +	p = memscan(data_char, '#', 64);
> +	*p = '\0';
> +
> +	return snprintf(buf, PAGE_SIZE, "%s\n", data_char);
> +}
> +
> +static ssize_t delta_flashkey_show(struct device *dev,
> +				 struct device_attribute *devattr,
> +				 char *buf)
> +{
> +	u8 reg;
> +	int rc;
> +	char *p;
> +	char data[I2C_SMBUS_BLOCK_MAX + 1];
> +	char data_char[2 * I2C_SMBUS_BLOCK_MAX + 1];
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +	rc = i2c_smbus_read_block_data(client, reg, data);
> +	if (rc < 0)
> +		return rc;
> +
> +	if (rc != 4)
> +		return -EPROTO;
> +
> +	char_to_char((data+1), data_char, (rc));
> +
> +	/* filled with printable characters, ending with # */
> +	p = memscan(data_char, '#', 8);
> +	*p = '\0';
> +
> +	return snprintf(buf, PAGE_SIZE, "%s\n", data_char);
> +}
> +
> +static int char_to_int(const char *buff)
> +{
> +	int i, index;
> +	int value = 0;
> +	const char *str;
> +
> +	if ((*buff == '0') && (*(buff+1) == 'x')) {
> +		index = 16;
> +		str = buff + 2;
> +	} else {
> +		index = 10;
> +		str = buff;
> +	}
> +
> +	for (i = 0; i < (strlen(str) - 1); i++) {
> +		if (*(str+i) >= '0' && *(str+i) <= '9')
> +			value = value * index + (*(str+i) - '0');
> +		else if (*(str+i) >= 'a' && *(str+i) <= 'f') {
> +			if (index == 16)
> +				value = value * index + (*(str+i) - 'a' + 10);
> +			else
> +				return -1;
> +		} else if (*(str+i) >= 'A' && *(str+i) <= 'F') {
> +			if (index == 16)
> +				value = value * index + (*(str+i) - 'A' + 10);
> +			else
> +				return -1;
> +		} else
> +			return -1;
> +	}
> +
> +	return value;
> +}
> +
> +static ssize_t delta_sendbyte_store(struct device *dev,
> +				struct device_attribute *devattr,
> +				const char *buf, size_t count)
> +{
> +	u8 reg;
> +	int rc;
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +
> +	rc = i2c_smbus_write_byte(client, reg);
> +	if (rc < 0)
> +		return rc;
> +	return count;
> +}
> +
> +static ssize_t delta_byte_store(struct device *dev,
> +				struct device_attribute *devattr,
> +				const char *buf, size_t count)
> +{
> +	u8 reg;
> +	int value;
> +	int rc;
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +
> +	value = char_to_int(buf);
> +
> +	rc = i2c_smbus_write_byte_data(client, reg, (u8)value);
> +	if (rc < 0)
> +		return rc;
> +	return count;
> +}
> +
> +static ssize_t delta_flashkey_store(struct device *dev,
> +				struct device_attribute *devattr,
> +				const char *buf, size_t count)
> +{
> +	u8 reg;
> +	u8 value[4];
> +	int rc;
> +	struct i2c_client *client = to_i2c_client(dev->parent);
> +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
> +
> +	reg = delta_regs[attr->index];
> +
> +	if (sysfs_streq("A5A5A5A5", buf)) {
> +		value[0] = 0xA5;
> +		value[1] = 0xA5;
> +		value[2] = 0xA5;
> +		value[3] = 0xA5;
> +		rc = i2c_smbus_write_block_data(client, reg, 4, value);
> +		if (rc < 0)
> +			return rc;
> +		return count;
> +	} else if (sysfs_streq("7E15DC42", buf)) {
> +		value[0] = 0x7E;
> +		value[1] = 0x15;
> +		value[2] = 0xDC;
> +		value[3] = 0x42;
> +		rc = i2c_smbus_write_block_data(client, reg, 4, value);
> +		if (rc < 0)
> +			return rc;
> +		return count;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static SENSOR_DEVICE_ATTR_RW(operation, delta_byte, operation);
> +static SENSOR_DEVICE_ATTR_WO(clear_fault, delta_sendbyte, clear_fault);
> +static SENSOR_DEVICE_ATTR_RW(write_protect, delta_byte, write_protect);
> +static SENSOR_DEVICE_ATTR_WO(store_default, delta_sendbyte, store_default);
> +static SENSOR_DEVICE_ATTR_RW(vo_ovfault_response, delta_byte, vo_ovfault_response);
> +static SENSOR_DEVICE_ATTR_RW(io_ocfault_response, delta_byte, io_ocfault_response);
> +static SENSOR_DEVICE_ATTR_RW(status_cml, delta_byte, status_cml);
> +static SENSOR_DEVICE_ATTR_RO(pmbus_revision, delta_byte, pmbus_revision);
> +static SENSOR_DEVICE_ATTR_RO(mfr_id, delta_string, mfr_id);
> +static SENSOR_DEVICE_ATTR_RO(mfr_model, delta_string, mfr_model);
> +static SENSOR_DEVICE_ATTR_RO(mfr_revision, delta_string, mfr_revision);
> +static SENSOR_DEVICE_ATTR_RO(mfr_location, delta_string, mfr_location);
> +static SENSOR_DEVICE_ATTR_WO(erase_blackbox, delta_sendbyte, erase_blackbox);
> +static SENSOR_DEVICE_ATTR_RO(read_blackbox, delta_blackbox, read_blackbox);
> +static SENSOR_DEVICE_ATTR_RO(read_event_num, delta_byte, read_event_num);
> +static SENSOR_DEVICE_ATTR_WO(set_event_num, delta_byte, set_event_num);
> +static SENSOR_DEVICE_ATTR_RW(flash_key, delta_flashkey, flash_key);
> +
> +static struct attribute *delta_attrs[] = {
> +	&sensor_dev_attr_operation.dev_attr.attr,
> +	&sensor_dev_attr_clear_fault.dev_attr.attr,
> +	&sensor_dev_attr_write_protect.dev_attr.attr,
> +	&sensor_dev_attr_store_default.dev_attr.attr,
> +	&sensor_dev_attr_vo_ovfault_response.dev_attr.attr,
> +	&sensor_dev_attr_io_ocfault_response.dev_attr.attr,
> +	&sensor_dev_attr_status_cml.dev_attr.attr,
> +	&sensor_dev_attr_pmbus_revision.dev_attr.attr,
> +	&sensor_dev_attr_mfr_id.dev_attr.attr,
> +	&sensor_dev_attr_mfr_model.dev_attr.attr,
> +	&sensor_dev_attr_mfr_revision.dev_attr.attr,
> +	&sensor_dev_attr_mfr_location.dev_attr.attr,
> +	&sensor_dev_attr_erase_blackbox.dev_attr.attr,
> +	&sensor_dev_attr_read_blackbox.dev_attr.attr,
> +	&sensor_dev_attr_read_event_num.dev_attr.attr,
> +	&sensor_dev_attr_set_event_num.dev_attr.attr,
> +	&sensor_dev_attr_flash_key.dev_attr.attr,
> +	NULL,
> +};
> +
> +ATTRIBUTE_GROUPS(delta);
> +
> +static const struct pmbus_driver_info delta_info[] = {
> +	[Q54SJ108A2] = {
> +		.pages = 1,
> +
> +		/* Source : Delta Q54SJ108A2 */
> +		.format[PSC_TEMPERATURE] = linear,
> +		.format[PSC_VOLTAGE_IN] = linear,
> +		.format[PSC_CURRENT_OUT] = linear,
> +
> +		.func[0] = PMBUS_HAVE_VIN |
> +		PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
> +		PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
> +		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
> +		PMBUS_HAVE_STATUS_INPUT,
> +
> +		.groups = delta_groups,
> +	},
> +};
> +
> +static int delta_probe(struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	struct device *dev = &client->dev;
> +	u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
> +	struct pmbus_driver_info *info;
> +	enum chips chip_id;
> +	int ret;
> +
> +	if (!i2c_check_functionality(client->adapter,
> +		I2C_FUNC_SMBUS_BYTE_DATA |
> +		I2C_FUNC_SMBUS_WORD_DATA |
> +		I2C_FUNC_SMBUS_BLOCK_DATA))
> +		return -ENODEV;
> +
> +	if (client->dev.of_node)
> +		chip_id = (enum chips)of_device_get_match_data(dev);
> +	else
> +		chip_id = id->driver_data;
> +
> +	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "Failed to read Manufacturer ID\n");
> +		return ret;
> +	}
> +	if (ret != 5 || strncmp(buf, "DELTA", 5)) {
> +		buf[ret] = '\0';
> +		dev_err(dev, "Unsupported Manufacturer ID '%s'\n", buf);
> +		return -ENODEV;
> +	}
> +
> +	/*
> +	 * The chips support reading PMBUS_MFR_MODEL.
> +	 */
> +	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to read Manufacturer Model\n");
> +		return ret;
> +	}
> +	if (ret != 14 || strncmp(buf, "Q54SJ108A2", 10)) {
> +		buf[ret] = '\0';
> +		dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);
> +		return -ENODEV;
> +	}
> +
> +	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_REVISION, buf);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to read Manufacturer Revision\n");
> +		return ret;
> +	}
> +
> +	if (ret != 4 || buf[0] != 'S') {
> +		buf[ret] = '\0';
> +		dev_err(dev, "Unsupported Manufacturer Revision '%s'\n", buf);
> +		return -ENODEV;
> +	}
> +
> +	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
> +
> +	if (!info)
> +		return -ENOMEM;
> +
> +	memcpy(info, &delta_info[chip_id], sizeof(*info));
> +
> +	return pmbus_do_probe(client, id, info);
> +
> +}
> +
> +static const struct i2c_device_id delta_id[] = {
> +	{ "Q54SJ108A2", Q54SJ108A2 },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, delta_id);
> +
> +static const struct of_device_id delta_of_match[] = {
> +	{ .compatible = "delta,Q54SJ108A2", .data = (void *)Q54SJ108A2 },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, delta_of_match);
> +
> +static struct i2c_driver delta_driver = {
> +	.driver = {
> +		.name = "Q54SJ108A2",
> +		.of_match_table = delta_of_match,
> +	},
> +	.probe = delta_probe,
> +	.remove = pmbus_do_remove,
> +	.id_table = delta_id,
> +};
> +
> +module_i2c_driver(delta_driver);
> +
> +MODULE_AUTHOR("Delta <734056705@...com>");
> +MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2NCAH / Q54SJ108A2NCDH / Q54SJ108A2NCPG / Q54SJ108A2NCPH");
> +MODULE_LICENSE("GPL");
> -- 
> 2.25.1
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ