All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 3/6] Add Advantech iManager HWmon driver
@ 2016-01-10  9:11 richard.dorsch
  2016-01-10 10:25   ` kbuild test robot
  2016-01-10 10:25   ` kbuild test robot
  0 siblings, 2 replies; 43+ messages in thread
From: richard.dorsch @ 2016-01-10  9:11 UTC (permalink / raw)
  To: linux-kernel
  Cc: lm-sensors, linux-i2c, linux-watchdog, linux-gpio, lee.jones,
	jdelvare, linux, wim, jo.sunga, Richard Vidal-Dorsch

From: Richard Vidal-Dorsch <richard.dorsch@gmail.com>

Signed-off-by: Richard Vidal-Dorsch <richard.dorsch@gmail.com>
---
 Documentation/hwmon/imanager       |   59 ++
 drivers/hwmon/Kconfig              |   12 +
 drivers/hwmon/Makefile             |    2 +
 drivers/hwmon/imanager-ec-hwmon.c  |  606 +++++++++++++++++++++
 drivers/hwmon/imanager-hwmon.c     | 1058 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/imanager/hwmon.h |  120 ++++
 6 files changed, 1857 insertions(+)
 create mode 100644 Documentation/hwmon/imanager
 create mode 100644 drivers/hwmon/imanager-ec-hwmon.c
 create mode 100644 drivers/hwmon/imanager-hwmon.c
 create mode 100644 include/linux/mfd/imanager/hwmon.h

diff --git a/Documentation/hwmon/imanager b/Documentation/hwmon/imanager
new file mode 100644
index 0000000..0705cf9
--- /dev/null
+++ b/Documentation/hwmon/imanager
@@ -0,0 +1,59 @@
+Kernel driver imanager_hwmon
+============================
+
+This platform driver provides support for iManager Hardware Monitoring
+and FAN control.
+
+This driver depends on imanager (mfd).
+
+Description
+-----------
+
+This driver provides support for the Advantech iManager Hardware Monitoring EC.
+
+The Advantech iManager supports up to 3 fan rotation speed sensors,
+3 temperature monitoring sources and up to 5 voltage sensors, VID, alarms and
+a automatic fan regulation strategy (as well as manual fan control mode).
+
+Temperatures are measured in degrees Celsius and measurement resolution is
+1 degC. An Alarm is triggered when the temperature gets higher than the high
+limit; it stays on until the temperature falls below the high limit.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. No fan
+speed divider support available.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+The driver supports automatic fan control mode known as Thermal Cruise.
+In this mode, the firmware attempts to keep the measured temperature in a
+predefined temperature range. If the temperature goes out of range, fan
+is driven slower/faster to reach the predefined range again.
+
+The mode works for fan1-fan3.
+
+sysfs attributes
+----------------
+
+pwm[1-3] - this file stores PWM duty cycle or DC value (fan speed) in range:
+	   0 (lowest speed) to 255 (full)
+
+pwm[1-3]_enable - this file controls mode of fan/temperature control:
+	* 0 Fan control disabled (fans set to maximum speed)
+	* 1 Manual mode, write to pwm[1-3] any value 0-255
+	* 2 "Fan Speed Cruise" mode
+
+pwm[1-3]_mode - controls if output is PWM or DC level
+        * 0 DC output
+        * 1 PWM output
+
+Speed Cruise mode (2)
+---------------------
+
+This mode tries to keep the fan speed constant within min/max speed.
+
+fan[1-3]_min - Minimum fan speed
+fan[1-3]_max - Maximum fan speed
+
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 80a73bf..776bb8a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -613,6 +613,18 @@ config SENSORS_CORETEMP
 	  sensor inside your CPU. Most of the family 6 CPUs
 	  are supported. Check Documentation/hwmon/coretemp for details.
 
+config SENSORS_IMANAGER
+	tristate "Advantech iManager Hardware Monitoring"
+	depends on MFD_IMANAGER
+	select HWMON_VID
+	help
+	  This enables support for Advantech iManager hardware monitoring
+	  of some Advantech SOM, MIO, AIMB, and PCM modules/boards.
+	  Requires mfd-core and imanager-core to function properly.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called imanager_hwmon.
+
 config SENSORS_IT87
 	tristate "ITE IT87xx and compatibles"
 	depends on !PPC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 12a3239..53752bc 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -76,6 +76,8 @@ obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
 obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
 obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
+imanager_hwmon-objs		:= imanager-hwmon.o imanager-ec-hwmon.o
+obj-$(CONFIG_SENSORS_IMANAGER)	+= imanager_hwmon.o
 obj-$(CONFIG_SENSORS_INA209)	+= ina209.o
 obj-$(CONFIG_SENSORS_INA2XX)	+= ina2xx.o
 obj-$(CONFIG_SENSORS_IT87)	+= it87.o
diff --git a/drivers/hwmon/imanager-ec-hwmon.c b/drivers/hwmon/imanager-ec-hwmon.c
new file mode 100644
index 0000000..1920835
--- /dev/null
+++ b/drivers/hwmon/imanager-ec-hwmon.c
@@ -0,0 +1,606 @@
+/*
+ * Advantech iManager Hardware Monitoring core
+ *
+ * Copyright (C) 2016 Advantech Co., Ltd., Irvine, CA, USA
+ * Author: Richard Vidal-Dorsch <richard.dorsch@advantech.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/byteorder/generic.h>
+#include <linux/swab.h>
+#include <linux/mfd/imanager/ec.h>
+#include <linux/mfd/imanager/hwmon.h>
+
+#define HWM_STATUS_UNDEFINED_ITEM	2UL
+#define HWM_STATUS_UNDEFINED_DID	3UL
+#define HWM_STATUS_UNDEFINED_HWPIN	4UL
+
+/*
+ * FAN defs
+ */
+
+struct fan_dev_config {
+	u8	did,
+		hwpin,
+		tachoid,
+		status,
+		control,
+		temp_max,
+		temp_min,
+		temp_stop,
+		pwm_max,
+		pwm_min;
+	u16	rpm_max;
+	u16	rpm_min;
+	u8	debounce;	/* debounce time, not used */
+	u8	temp;		/* Current Thermal Zone Temperature */
+	u16	rpm_target;	/* RPM Target Speed, not used */
+};
+
+struct fan_status {
+	u32	sysctl	: 1,	/* System Control flag */
+		tacho	: 1,	/* FAN tacho source defined */
+		pulse	: 1,	/* FAN pulse type defined */
+		thermal	: 1,	/* Thermal zone init */
+		i2clink	: 1,	/* I2C protocol fail flag (thermal sensor) */
+		dnc	: 1,	/* don't care */
+		mode	: 2;	/* FAN Control mode */
+};
+
+struct fan_alert_limit {
+	u16	fan0_min,
+		fan0_max,
+		fan1_min,
+		fan1_max,
+		fan2_min,
+		fan2_max;
+};
+
+struct fan_alert_flag {
+	u32	fan0_min_alarm	: 1,
+		fan0_max_alarm	: 1,
+		fan1_min_alarm	: 1,
+		fan1_max_alarm	: 1,
+		fan2_min_alarm	: 1,
+		fan2_max_alarm	: 1,
+		dnc		: 2; /* don't care */
+};
+
+/*----------------------------------------------------*
+ * FAN Control bit field                              *
+ * enable:   0:Disabled, 1:Enabled                    *
+ * type:     0:PWM,      1:RPM                        *
+ * pulse:    0:Undefined 1:2 Pulse   2:4 Pulse        *
+ * tacho:    1:CPU FAN,  2:SYS1 FAN, 3:SYS2 FAN       *
+ * mode:     0:Off,      1:Full,     2:Manual, 3:Auto *
+ *- 7  6 ---- 5  4 --- 3  2 ----- 1 -------- 0 -------*
+ *  MODE   | TACHO  |  PULSE  |  TYPE  |    ENABLE    *
+ *----------------------------------------------------*/
+struct fan_ctrl {
+	u32	enable	: 1,	/* SmartFAN control on/off */
+		type	: 1,	/* FAN control type [0, 1] PWM/RPM */
+		pulse	: 2,	/* FAN pulse [0..2] */
+		tacho	: 2,	/* FAN Tacho Input [1..3] */
+		mode	: 2;	/* off/full/manual/auto */
+};
+
+enum fan_dev_ctrl {
+	CTRL_STATE = 3,
+	OPMODE,
+	IDSENSOR,
+	ACTIVE,
+	CTRL_MODE,
+};
+
+enum fan_limit {
+	LIMIT_PWM,
+	LIMIT_RPM,
+	LIMIT_TEMP,
+};
+
+static const char * const fan_temp_label[] = {
+	"Temp CPU",
+	"Temp SYS1",
+	"Temp SYS2",
+	NULL,
+};
+
+static const struct imanager_hwmon_device *hwmon;
+
+static inline int hwm_get_adc_value(u8 did)
+{
+	return imanager_read_word(EC_CMD_HWP_RD, did);
+}
+
+static inline int hwm_get_rpm_value(u8 did)
+{
+	return imanager_read_word(EC_CMD_HWP_RD, did);
+}
+
+static inline int hwm_get_pwm_value(u8 did)
+{
+	return imanager_read_byte(EC_CMD_HWP_RD, did);
+}
+
+static inline int hwm_set_pwm_value(u8 did, u8 val)
+{
+	return imanager_write_byte(EC_CMD_HWP_WR, did, val);
+}
+
+static int hwm_read_fan_config(int num, struct fan_dev_config *cfg)
+{
+	int ret;
+	struct ec_message msg = {
+		.rlen = 0xff, /* use alternative message body */
+		.wlen = 0,
+	};
+	struct fan_dev_config *_cfg = (struct fan_dev_config *)&msg.u.data;
+
+	if (WARN_ON(!cfg))
+		return -EINVAL;
+
+	memset(cfg, 0, sizeof(struct fan_dev_config));
+
+	ret = imanager_msg_read(EC_CMD_FAN_CTL_RD, num, &msg);
+	if (ret)
+		return ret;
+
+	if (!_cfg->did) {
+		pr_err("Invalid FAN%d device ID - possible firmware bug\n",
+			num);
+		return -ENODEV;
+	}
+
+	memcpy(cfg, &msg.u.data, sizeof(struct fan_dev_config));
+
+	return 0;
+}
+
+static int hwm_write_fan_config(int fnum, struct fan_dev_config *cfg)
+{
+	int ret;
+	struct ec_message msg = {
+		.rlen = 0,
+		.wlen = sizeof(struct fan_dev_config),
+	};
+
+	if (!cfg->did)
+		return -ENODEV;
+
+	msg.data = (u8 *)cfg;
+
+	ret = imanager_msg_write(EC_CMD_FAN_CTL_WR, fnum, &msg);
+	if (ret < 0)
+		return ret;
+
+	switch (ret) {
+	case 0:
+		break;
+	case HWM_STATUS_UNDEFINED_ITEM:
+	case HWM_STATUS_UNDEFINED_DID:
+	case HWM_STATUS_UNDEFINED_HWPIN:
+		return -EFAULT;
+	default:
+		pr_err("Unknown error status of fan%d (%d)\n", fnum, ret);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline void hwm_set_temp_limit(struct fan_dev_config *cfg,
+				      const struct hwm_fan_temp_limit *temp)
+{
+	cfg->temp_stop = temp->stop;
+	cfg->temp_min  = temp->min;
+	cfg->temp_max  = temp->max;
+}
+
+static inline void hwm_set_pwm_limit(struct fan_dev_config *cfg,
+				     const struct hwm_fan_limit *pwm)
+{
+	cfg->pwm_min = pwm->min;
+	cfg->pwm_max = pwm->max;
+}
+
+static inline void hwm_set_rpm_limit(struct fan_dev_config *cfg,
+				     const struct hwm_fan_limit *rpm)
+{
+	cfg->rpm_min = swab16(rpm->min);
+	cfg->rpm_max = swab16(rpm->max);
+}
+
+static inline void hwm_set_limit(struct fan_dev_config *cfg,
+				 const struct hwm_sensors_limit *limit)
+{
+	hwm_set_temp_limit(cfg, &limit->temp);
+	hwm_set_pwm_limit(cfg, &limit->pwm);
+	hwm_set_rpm_limit(cfg, &limit->rpm);
+}
+
+static int hwm_core_get_fan_alert_flag(struct fan_alert_flag *flag)
+{
+	int ret;
+	u8 *value = (u8 *)flag;
+
+	ret = imanager_acpiram_read_byte(EC_ACPIRAM_FAN_ALERT);
+	if (ret < 0)
+		return ret;
+
+	*value = ret;
+
+	return 0;
+}
+
+static int hwm_core_get_fan_alert_limit(int fnum,
+					struct hwm_smartfan *fan)
+{
+	int ret;
+	struct fan_alert_limit limit;
+	struct fan_alert_flag flag;
+
+	ret = imanager_acpiram_read_block(EC_ACPIRAM_FAN_SPEED_LIMIT,
+					 (u8 *)&limit, sizeof(limit));
+	if (ret < 0)
+		return ret;
+
+	ret = hwm_core_get_fan_alert_flag(&flag);
+	if (ret < 0)
+		return ret;
+
+	switch (fnum) {
+	case FAN_CPU:
+		fan->alert.min = swab16(limit.fan0_min);
+		fan->alert.max = swab16(limit.fan0_max);
+		fan->alert.min_alarm = flag.fan0_min_alarm;
+		fan->alert.max_alarm = flag.fan0_max_alarm;
+		break;
+	case FAN_SYS1:
+		fan->alert.min = swab16(limit.fan1_min);
+		fan->alert.max = swab16(limit.fan1_max);
+		fan->alert.min_alarm = flag.fan1_min_alarm;
+		fan->alert.max_alarm = flag.fan1_max_alarm;
+		break;
+	case FAN_SYS2:
+		fan->alert.min = swab16(limit.fan2_min);
+		fan->alert.max = swab16(limit.fan2_max);
+		fan->alert.min_alarm = flag.fan2_min_alarm;
+		fan->alert.max_alarm = flag.fan2_max_alarm;
+		break;
+	default:
+		pr_err("Unknown FAN ID %d\n", fnum);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hwm_core_fan_set_alert_limit(int fnum,
+					struct hwm_fan_alert *alert)
+{
+	int ret;
+	struct fan_alert_limit limit;
+
+	ret = imanager_acpiram_read_block(EC_ACPIRAM_FAN_SPEED_LIMIT,
+					 (u8 *)&limit, sizeof(limit));
+	if (ret < 0)
+		return ret;
+
+	switch (fnum) {
+	case FAN_CPU:
+		limit.fan0_min = swab16(alert->min);
+		limit.fan0_max = swab16(alert->max);
+		break;
+	case FAN_SYS1:
+		limit.fan1_min = swab16(alert->min);
+		limit.fan1_max = swab16(alert->max);
+		break;
+	case FAN_SYS2:
+		limit.fan2_min = swab16(alert->min);
+		limit.fan2_max = swab16(alert->max);
+		break;
+	default:
+		pr_err("Unknown FAN ID %d\n", fnum);
+		return -EINVAL;
+	}
+
+	return imanager_acpiram_write_block(EC_ACPIRAM_FAN_SPEED_LIMIT,
+					   (u8 *)&limit, sizeof(limit));
+}
+
+/* HWM CORE API */
+
+const char *hwm_core_adc_get_label(int num)
+{
+	if (WARN_ON(num >= hwmon->adc.num))
+		return NULL;
+
+	return hwmon->adc.attr[num].label;
+}
+
+const char *hwm_core_fan_get_label(int num)
+{
+	if (WARN_ON(num >= hwmon->fan.num))
+		return NULL;
+
+	return hwmon->fan.attr[num].label;
+}
+
+const char *hwm_core_fan_get_temp_label(int num)
+{
+	if (WARN_ON(num >= hwmon->fan.num))
+		return NULL;
+
+	return fan_temp_label[num];
+}
+
+int hwm_core_adc_is_available(int num)
+{
+	if (num >= EC_HWM_MAX_ADC)
+		return -EINVAL;
+
+	return hwmon->adc.attr[num].did ? 0 : -ENODEV;
+}
+
+int hwm_core_adc_get_value(int num, struct hwm_voltage *volt)
+{
+	int ret;
+
+	volt->valid = false;
+
+	ret = hwm_core_adc_is_available(num);
+	if (ret < 0)
+		return ret;
+
+	ret = hwm_get_adc_value(hwmon->adc.attr[num].did);
+	if (ret < 0)
+		return ret;
+
+	volt->value = ret * hwmon->adc.attr[num].scale;
+	volt->valid = true;
+
+	return 0;
+}
+
+int hwm_core_fan_get_ctrl(int num, struct hwm_smartfan *fan)
+{
+	int ret;
+	struct fan_dev_config cfg;
+	struct fan_ctrl *ctrl = (struct fan_ctrl *)&cfg.control;
+
+	if (WARN_ON((num >= HWM_MAX_FAN) || !fan))
+		return -EINVAL;
+
+	memset(fan, 0, sizeof(struct hwm_smartfan));
+
+	ret = hwm_read_fan_config(num, &cfg);
+	if (ret < 0)
+		return ret;
+
+	fan->pulse = ctrl->pulse;
+	fan->type = ctrl->type;
+
+	/*
+	 * It seems that fan->mode does not always report the correct
+	 * FAN mode so the only way of reporting the current FAN mode
+	 * is to read back ctrl->mode.
+	 */
+	fan->mode = ctrl->mode;
+
+	ret = hwm_get_rpm_value(cfg.tachoid);
+	if (ret < 0) {
+		pr_err("Failed to read FAN speed\n");
+		return ret;
+	}
+
+	fan->speed = ret;
+
+	ret = hwm_get_pwm_value(hwmon->fan.attr[num].did);
+	if (ret < 0) {
+		pr_err("Failed to read FAN%d PWM\n", num);
+		return ret;
+	}
+
+	fan->pwm = ret;
+
+	fan->alarm = (fan->pwm && !fan->speed) ? 1 : 0;
+
+	fan->limit.temp.min	= cfg.temp_min;
+	fan->limit.temp.max	= cfg.temp_max;
+	fan->limit.temp.stop	= cfg.temp_stop;
+	fan->limit.pwm.min	= cfg.pwm_min;
+	fan->limit.pwm.max	= cfg.pwm_max;
+	fan->limit.rpm.min	= swab16(cfg.rpm_min);
+	fan->limit.rpm.max	= swab16(cfg.rpm_max);
+
+	ret = hwm_core_get_fan_alert_limit(num, fan);
+	if (ret)
+		return ret;
+
+	fan->valid = true;
+
+	return 0;
+}
+
+int hwm_core_fan_set_ctrl(int num, int fmode, int ftype, int pwm, int pulse,
+			  struct hwm_sensors_limit *limit,
+			  struct hwm_fan_alert *alert)
+{
+	int ret;
+	struct fan_dev_config cfg;
+	struct fan_ctrl *ctrl = (struct fan_ctrl *)&cfg.control;
+	struct hwm_sensors_limit _limit = { {0, 0, 0}, {0, 0}, {0, 0} };
+
+	if (WARN_ON(num >= HWM_MAX_FAN))
+		return -EINVAL;
+
+	ret = hwm_read_fan_config(num, &cfg);
+	if (ret < 0) {
+		pr_err("Failed while reading FAN %s config\n",
+			hwmon->fan.attr[num].label);
+		return ret;
+	}
+
+	if (!limit)
+		limit = &_limit;
+
+	switch (fmode) {
+	case MODE_OFF:
+		ctrl->type = CTRL_PWM;
+		ctrl->mode = MODE_OFF;
+		break;
+	case MODE_FULL:
+		ctrl->type = CTRL_PWM;
+		ctrl->mode = MODE_FULL;
+		break;
+	case MODE_MANUAL:
+		ctrl->type = CTRL_PWM;
+		ctrl->mode = MODE_MANUAL;
+		ret = hwm_set_pwm_value(hwmon->fan.attr[num].did, pwm);
+		if (ret < 0)
+			return ret;
+		break;
+	case MODE_AUTO:
+		switch (ftype) {
+		case CTRL_PWM:
+			limit->rpm.min = 0;
+			limit->rpm.max = 0;
+			ctrl->type = CTRL_PWM;
+			break;
+		case CTRL_RPM:
+			limit->pwm.min = 0;
+			limit->pwm.max = 0;
+			ctrl->type = CTRL_RPM;
+			break;
+		default:
+			return -EINVAL;
+		}
+		ctrl->mode = MODE_AUTO;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	hwm_set_limit(&cfg, limit);
+
+	ctrl->pulse = (pulse && (pulse < 3)) ? pulse : 0;
+	ctrl->enable = 1;
+
+	ret = hwm_write_fan_config(num, &cfg);
+	if (ret < 0)
+		return ret;
+
+	if (alert)
+		return hwm_core_fan_set_alert_limit(num, alert);
+
+	return 0;
+}
+
+int hwm_core_fan_is_available(int num)
+{
+	if (WARN_ON(num >= HWM_MAX_FAN))
+		return -EINVAL;
+
+	return hwmon->fan.active & (1 << num) &&
+		hwmon->fan.attr[num].did ? 0 : -ENODEV;
+}
+
+static int hwm_core_fan_set_limit(int num, int fan_limit,
+				  struct hwm_sensors_limit *limit)
+{
+	struct fan_dev_config cfg;
+	int ret;
+
+	if (WARN_ON(num >= HWM_MAX_FAN))
+		return -EINVAL;
+
+	ret = hwm_read_fan_config(num, &cfg);
+	if (ret < 0) {
+		pr_err("Failed while reading FAN %s config\n",
+			hwmon->fan.attr[num].label);
+		return ret;
+	}
+
+	switch (fan_limit) {
+	case LIMIT_PWM:
+		hwm_set_pwm_limit(&cfg, &limit->pwm);
+		break;
+	case LIMIT_RPM:
+		hwm_set_rpm_limit(&cfg, &limit->rpm);
+		break;
+	case LIMIT_TEMP:
+		hwm_set_temp_limit(&cfg, &limit->temp);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return hwm_write_fan_config(num, &cfg);
+}
+
+int hwm_core_fan_set_rpm_limit(int num, int min, int max)
+{
+	struct hwm_sensors_limit limit = {
+		.rpm = {
+			.min = min,
+			.max = max,
+		},
+	};
+
+	return hwm_core_fan_set_limit(num, LIMIT_RPM, &limit);
+}
+
+int hwm_core_fan_set_pwm_limit(int num, int min, int max)
+{
+	struct hwm_sensors_limit limit = {
+		.pwm = {
+			.min = min,
+			.max = max,
+		},
+	};
+
+	return hwm_core_fan_set_limit(num, LIMIT_PWM, &limit);
+}
+
+int hwm_core_fan_set_temp_limit(int num, int stop, int min, int max)
+{
+	struct hwm_sensors_limit limit = {
+		.temp = {
+			.stop = stop,
+			.min = min,
+			.max = max,
+		},
+	};
+
+	return hwm_core_fan_set_limit(num, LIMIT_TEMP, &limit);
+}
+
+int hwm_core_adc_get_max_count(void)
+{
+	return hwmon->adc.num;
+}
+
+int hwm_core_fan_get_max_count(void)
+{
+	return hwmon->fan.num;
+}
+
+int hwm_core_init(void)
+{
+	hwmon = imanager_get_hwmon_device();
+	if (!hwmon)
+		return -ENODEV;
+
+	return 0;
+}
+
diff --git a/drivers/hwmon/imanager-hwmon.c b/drivers/hwmon/imanager-hwmon.c
new file mode 100644
index 0000000..b8ad562
--- /dev/null
+++ b/drivers/hwmon/imanager-hwmon.c
@@ -0,0 +1,1058 @@
+/*
+ * Advantech iManager Hardware Monitoring driver
+ * Derived from nct6775 driver
+ *
+ * Copyright (C) 2016 Advantech Co., Ltd., Irvine, CA, USA
+ * Author: Richard Vidal-Dorsch <richard.dorsch@advantech.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/mfd/imanager/core.h>
+#include <linux/mfd/imanager/hwmon.h>
+
+struct imanager_hwmon_data {
+	struct imanager_device_data *idev;
+	bool valid;	/* if set, below values are valid */
+	struct hwm_data hwm;
+	int adc_num;
+	int fan_num;
+	unsigned long samples;
+	unsigned long last_updated;
+	const struct attribute_group *groups[3];
+};
+
+static inline u32 in_from_reg(u16 val)
+{
+	return clamp_val(DIV_ROUND_CLOSEST(val * SCALE_IN, 1000), 0, 65535);
+}
+
+static inline u16 in_to_reg(u32 val)
+{
+	return clamp_val(DIV_ROUND_CLOSEST(val * 1000, SCALE_IN), 0, 65535);
+}
+
+static struct imanager_hwmon_data *
+imanager_hwmon_update_device(struct device *dev)
+{
+	struct imanager_hwmon_data *data = dev_get_drvdata(dev);
+	int i;
+
+	mutex_lock(&data->idev->lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+	    || !data->valid) {
+		/* Measured voltages */
+		for (i = 0; i < data->adc_num; i++)
+			hwm_core_adc_get_value(i, &data->hwm.volt[i]);
+
+		/* Measured fan speeds */
+		for (i = 0; i < data->fan_num; i++)
+			hwm_core_fan_get_ctrl(i, &data->hwm.fan[i]);
+
+		data->last_updated = jiffies;
+		data->valid = true;
+	}
+
+	mutex_unlock(&data->idev->lock);
+
+	return data;
+}
+
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+
+	return sprintf(buf, "%u\n", in_from_reg(adc->value));
+}
+
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+
+	return sprintf(buf, "%u\n", in_from_reg(adc->min));
+}
+
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+
+	return sprintf(buf, "%u\n", in_from_reg(adc->max));
+}
+
+static ssize_t
+store_in_min(struct device *dev, struct device_attribute *attr,
+	     const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->idev->lock);
+
+	adc->min = in_to_reg(val);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+store_in_max(struct device *dev, struct device_attribute *attr,
+	     const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->idev->lock);
+
+	adc->max = in_to_reg(val);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_in_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+	int val = 0;
+
+	if (adc->valid)
+		val = (adc->value < adc->min) || (adc->value > adc->max);
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+show_in_average(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+
+	if (adc->average)
+		adc->average =
+			DIV_ROUND_CLOSEST(adc->average * data->samples +
+					  adc->value, ++data->samples);
+	else {
+		adc->average = adc->value;
+		data->samples = 1;
+	}
+
+	return sprintf(buf, "%u\n", in_from_reg(adc->average));
+}
+
+static ssize_t
+show_in_lowest(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+
+	if (!adc->lowest)
+		adc->lowest = adc->highest = adc->value;
+	else if (adc->value < adc->lowest)
+		adc->lowest = adc->value;
+
+	return sprintf(buf, "%u\n", in_from_reg(adc->lowest));
+}
+
+static ssize_t
+show_in_highest(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+
+	if (!adc->highest)
+		adc->highest = adc->value;
+	else if (adc->value > adc->highest)
+		adc->highest = adc->value;
+
+	return sprintf(buf, "%u\n", in_from_reg(adc->highest));
+}
+
+static ssize_t
+store_in_reset_history(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_voltage *adc = &data->hwm.volt[index];
+	unsigned long val;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	mutex_lock(&data->idev->lock);
+
+	if (val == 1) {
+		adc->lowest = 0;
+		adc->highest = 0;
+	} else {
+		count = -EINVAL;
+	}
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+
+	return sprintf(buf, "%u\n", fan->temp * 1000);
+}
+
+static ssize_t
+show_fan_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+
+	return sprintf(buf, "%u\n", fan->valid ? fan->speed : 0);
+}
+
+static inline int is_alarm(const struct hwm_smartfan *fan)
+{
+	/*
+	 * Do not set ALARM flag if FAN is in speed cruise mode (3)
+	 * as this mode automatically turns on the FAN
+	 * Set ALARM flag when pwm is set but speed is 0 as this
+	 * could be a defective FAN or no FAN is present
+	 */
+	return (!fan->valid ||
+		((fan->mode == MODE_AUTO) && fan->alarm) ||
+		(fan->speed > fan->limit.rpm.max));
+}
+
+static ssize_t
+show_fan_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+
+	return sprintf(buf, "%u\n", fan->valid ? is_alarm(fan) : 0);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_fan_limit *rpm = &data->hwm.fan[index - 1].limit.rpm;
+
+	return sprintf(buf, "%u\n", rpm->min);
+}
+
+static ssize_t
+show_fan_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_fan_limit *rpm = &data->hwm.fan[index - 1].limit.rpm;
+
+	return sprintf(buf, "%u\n", rpm->max);
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+	struct hwm_fan_limit *rpm = &fan->limit.rpm;
+	unsigned long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* do not apply value if not in 'fan cruise mode' */
+	if (fan->mode != MODE_AUTO)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_rpm_limit(index - 1, val, rpm->max);
+	hwm_core_fan_get_ctrl(index - 1, fan); /* update */
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+store_fan_max(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+	struct hwm_fan_limit *rpm = &fan->limit.rpm;
+	unsigned long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	/* do not apply value if not in 'fan cruise mode' */
+	if (fan->mode != MODE_AUTO)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_rpm_limit(index - 1, rpm->min, val);
+	hwm_core_fan_get_ctrl(index - 1, fan);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	u32 val = DIV_ROUND_CLOSEST(data->hwm.fan[index - 1].pwm * 255, 100);
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+	unsigned long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val * 100, 255);
+
+	mutex_lock(&data->idev->lock);
+
+	switch (fan->mode) {
+	case MODE_MANUAL:
+		hwm_core_fan_set_ctrl(index - 1, MODE_MANUAL, CTRL_PWM,
+				      val, 0, NULL, NULL);
+		break;
+	case MODE_AUTO:
+		if (fan->type == CTRL_RPM)
+			break;
+		hwm_core_fan_set_ctrl(index - 1, MODE_AUTO, CTRL_PWM,
+				      val, 0, &fan->limit, &fan->alert);
+		break;
+	}
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%u\n", data->hwm.fan[index - 1].limit.pwm.min);
+}
+
+static ssize_t
+show_pwm_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%u\n", data->hwm.fan[index - 1].limit.pwm.max);
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	struct hwm_smartfan *fan = &data->hwm.fan[nr];
+
+	if (fan->mode == MODE_OFF)
+		return -EINVAL;
+
+	return sprintf(buf, "%u\n", fan->mode - 1);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	struct hwm_smartfan *fan = &data->hwm.fan[nr];
+	unsigned long mode = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &mode);
+	if (err < 0)
+		return err;
+
+	if (mode > MODE_AUTO)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	switch (mode) {
+	case 0:
+		if (mode != 0)
+			hwm_core_fan_set_ctrl(nr, MODE_FULL, CTRL_PWM, 100,
+					      fan->pulse, NULL, NULL);
+		break;
+	case 1:
+		if (mode != 1)
+			hwm_core_fan_set_ctrl(nr, MODE_MANUAL, CTRL_PWM, 0,
+					      fan->pulse, NULL, NULL);
+		break;
+	case 2:
+		if (mode != 2)
+			hwm_core_fan_set_ctrl(nr, MODE_AUTO, fan->type, 0,
+					      fan->pulse, &fan->limit, NULL);
+		break;
+	}
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_smartfan *fan = &data->hwm.fan[index - 1];
+
+	if (fan->mode == MODE_OFF)
+		return -EINVAL;
+
+	return sprintf(buf, "%u\n", fan->type == CTRL_PWM ? 1 : 0);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	struct hwm_smartfan *fan = &data->hwm.fan[nr];
+	unsigned long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	if (fan->mode != MODE_AUTO)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_ctrl(nr, fan->mode, val ? CTRL_RPM : CTRL_PWM,
+			      fan->pwm, fan->pulse, &fan->limit, &fan->alert);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_temp_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	int val = data->hwm.fan[nr].limit.temp.min;
+
+	return sprintf(buf, "%d\n", val * 1000);
+}
+
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	int val = data->hwm.fan[nr].limit.temp.max;
+
+	return sprintf(buf, "%u\n", val * 1000);
+}
+
+static ssize_t
+show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	struct hwm_smartfan *fan = &data->hwm.fan[nr];
+	struct hwm_fan_temp_limit *temp = &fan->limit.temp;
+
+	return sprintf(buf, "%u\n", (fan->temp && (fan->temp >= temp->max)));
+}
+
+static ssize_t
+store_temp_min(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	struct hwm_smartfan *fan = &data->hwm.fan[nr];
+	struct hwm_fan_temp_limit *temp = &fan->limit.temp;
+	long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val, 1000);
+
+	if (val > 100)
+		return -EINVAL;
+
+	/* do not apply value if not in 'fan cruise mode' */
+	if (fan->mode != MODE_AUTO)
+		return -EINVAL;
+
+	/* The EC imanager provides three different temperature limit values
+	 * (stop, min, and max) where stop indicates a minimum temp value
+	 * (threshold) from which the FAN will turn off.  We are setting
+	 * temp_stop to the same value as temp_min.
+	 */
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_temp_limit(nr, val, val, temp->max);
+	hwm_core_fan_get_ctrl(nr, fan);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+store_temp_max(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int nr = to_sensor_dev_attr(attr)->index - 1;
+	struct hwm_smartfan *fan = &data->hwm.fan[nr];
+	struct hwm_fan_temp_limit *temp = &fan->limit.temp;
+	long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val, 1000);
+
+	if (val > 100)
+		return -EINVAL;
+
+	/* do not apply value if not in 'fan cruise mode' */
+	if (fan->mode != MODE_AUTO)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_temp_limit(nr, temp->stop, temp->min, val);
+	hwm_core_fan_get_ctrl(nr, fan);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+store_pwm_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_fan_limit *pwm = &data->hwm.fan[index - 1].limit.pwm;
+	long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val * 100, 255);
+
+	if (val > 100)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_pwm_limit(index - 1, val, pwm->max);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+store_pwm_max(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct imanager_hwmon_data *data = imanager_hwmon_update_device(dev);
+	int index = to_sensor_dev_attr(attr)->index;
+	struct hwm_fan_limit *pwm = &data->hwm.fan[index - 1].limit.pwm;
+	long val = 0;
+	int err;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	val = DIV_ROUND_CLOSEST(val * 100, 255);
+
+	if (val > 100)
+		return -EINVAL;
+
+	mutex_lock(&data->idev->lock);
+
+	hwm_core_fan_set_pwm_limit(index - 1, pwm->min, val);
+
+	mutex_unlock(&data->idev->lock);
+
+	return count;
+}
+
+static ssize_t
+show_in_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%s\n", hwm_core_adc_get_label(index));
+}
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%s\n", hwm_core_fan_get_temp_label(index - 1));
+}
+
+static ssize_t
+show_fan_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int index = to_sensor_dev_attr(attr)->index;
+
+	return sprintf(buf, "%s\n", hwm_core_fan_get_label(index - 1));
+}
+
+/*
+ * Sysfs callback functions
+ */
+
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_in_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min,
+			  store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max,
+			  store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_in_alarm, NULL, 0);
+
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_in_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min,
+			  store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max,
+			  store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_in_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min,
+			  store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max,
+			  store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_in_alarm, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, show_temp_min,
+			  store_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
+			  store_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, show_temp_min,
+			  store_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
+			  store_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, show_temp_min,
+			  store_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
+			  store_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, show_fan_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+			  store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
+			  store_fan_max, 1);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, show_fan_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+			  store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
+			  store_fan_max, 2);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(fan3_label, S_IRUGO, show_fan_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+			  store_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max,
+			  store_fan_max, 3);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IWUSR | S_IRUGO, show_pwm_min,
+			  store_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IWUSR | S_IRUGO, show_pwm_max,
+			  store_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+			  store_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+			  store_pwm_mode, 1);
+
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm2_min, S_IWUSR | S_IRUGO, show_pwm_min,
+			  store_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm2_max, S_IWUSR | S_IRUGO, show_pwm_max,
+			  store_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+			  store_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+			  store_pwm_mode, 2);
+
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3);
+static SENSOR_DEVICE_ATTR(pwm3_min, S_IWUSR | S_IRUGO, show_pwm_min,
+			  store_pwm_min, 3);
+static SENSOR_DEVICE_ATTR(pwm3_max, S_IWUSR | S_IRUGO, show_pwm_max,
+			  store_pwm_max, 3);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+			  store_pwm_enable, 3);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+			  store_pwm_mode, 3);
+
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(curr1_min, S_IWUSR | S_IRUGO, show_in_min,
+			  store_in_min, 4);
+static SENSOR_DEVICE_ATTR(curr1_max, S_IWUSR | S_IRUGO, show_in_max,
+			  store_in_max, 4);
+static SENSOR_DEVICE_ATTR(curr1_alarm, S_IRUGO, show_in_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(curr1_average, S_IRUGO, show_in_average, NULL, 4);
+static SENSOR_DEVICE_ATTR(curr1_lowest, S_IRUGO, show_in_lowest, NULL, 4);
+static SENSOR_DEVICE_ATTR(curr1_highest, S_IRUGO, show_in_highest, NULL, 4);
+static SENSOR_DEVICE_ATTR(curr1_reset_history, S_IWUSR, NULL,
+			  store_in_reset_history, 4);
+
+static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_in, NULL, 3);
+
+static struct attribute *imanager_in_attributes[] = {
+	&sensor_dev_attr_in0_label.dev_attr.attr,
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in0_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in1_label.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_in2_label.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+	NULL
+};
+
+static umode_t
+imanager_in_is_visible(struct kobject *kobj, struct attribute *attr, int index)
+{
+	int max_count = hwm_core_adc_get_max_count();
+
+	if (max_count >= 3)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group imanager_group_in = {
+	.attrs = imanager_in_attributes,
+	.is_visible = imanager_in_is_visible,
+};
+
+static struct attribute *imanager_other_attributes[] = {
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_min.dev_attr.attr,
+	&sensor_dev_attr_curr1_max.dev_attr.attr,
+	&sensor_dev_attr_curr1_alarm.dev_attr.attr,
+	&sensor_dev_attr_curr1_average.dev_attr.attr,
+	&sensor_dev_attr_curr1_lowest.dev_attr.attr,
+	&sensor_dev_attr_curr1_highest.dev_attr.attr,
+	&sensor_dev_attr_curr1_reset_history.dev_attr.attr,
+
+	&sensor_dev_attr_cpu0_vid.dev_attr.attr,
+
+	NULL
+};
+
+static umode_t
+imanager_other_is_visible(struct kobject *kobj,
+			  struct attribute *attr, int index)
+{
+	int max_count = hwm_core_adc_get_max_count();
+
+	/*
+	 * There are either 3 or 5 VINs
+	 * vin3 is current monitoring
+	 * vin4 is CPU VID
+	 */
+	if (max_count > 3)
+		return attr->mode;
+
+	return 0;
+}
+
+static const struct attribute_group imanager_group_other = {
+	.attrs = imanager_other_attributes,
+	.is_visible = imanager_other_is_visible,
+};
+
+static struct attribute *imanager_fan_attributes[] = {
+	&sensor_dev_attr_fan1_label.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_max.dev_attr.attr,
+	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_fan2_label.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_max.dev_attr.attr,
+	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_fan3_label.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_max.dev_attr.attr,
+	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp1_label.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp2_label.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_label.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_min.dev_attr.attr,
+	&sensor_dev_attr_pwm1_max.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm2_min.dev_attr.attr,
+	&sensor_dev_attr_pwm2_max.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_mode.dev_attr.attr,
+
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+	&sensor_dev_attr_pwm3_min.dev_attr.attr,
+	&sensor_dev_attr_pwm3_max.dev_attr.attr,
+	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm3_mode.dev_attr.attr,
+
+	NULL
+};
+
+static umode_t
+imanager_fan_is_visible(struct kobject *kobj, struct attribute *attr, int index)
+{
+	int err;
+
+	if ((index >= 0) && (index <= 14)) { /* fan */
+		err = hwm_core_fan_is_available(index / 5);
+		if (err < 0)
+			return 0;
+	} else if ((index >= 15) && (index <= 29)) { /* temp */
+		err = hwm_core_fan_is_available((index - 15) / 5);
+		if (err < 0)
+			return 0;
+	} else if ((index >= 30) && (index <= 34)) { /* pwm */
+		err = hwm_core_fan_is_available((index - 30) / 5);
+		if (err < 0)
+			return 0;
+	}
+
+	return attr->mode;
+}
+
+static const struct attribute_group imanager_group_fan = {
+	.attrs = imanager_fan_attributes,
+	.is_visible = imanager_fan_is_visible,
+};
+
+/*
+ * Module stuff
+ */
+static int imanager_hwmon_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct imanager_device_data *idev = dev_get_drvdata(dev->parent);
+	struct imanager_hwmon_data *data;
+	struct device *hwmon_dev;
+	int err, i, num_attr_groups = 0;
+
+	if (!idev) {
+		dev_err(dev, "Invalid platform data\n");
+		return -EINVAL;
+	}
+
+	err = hwm_core_init();
+	if (err) {
+		dev_err(dev, "Hwmon core init failed\n");
+		return -EIO;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct imanager_hwmon_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->idev = idev;
+	platform_set_drvdata(pdev, data);
+
+	data->adc_num = hwm_core_adc_get_max_count();
+	data->fan_num = hwm_core_fan_get_max_count();
+
+	for (i = 0; i < data->fan_num; i++) {
+		/* set active fan to automatic speed control */
+		hwm_core_fan_set_ctrl(i, MODE_AUTO, CTRL_RPM, 0, 0,
+				      NULL, NULL);
+		hwm_core_fan_get_ctrl(i, &data->hwm.fan[i]);
+	}
+
+	data->groups[num_attr_groups++] = &imanager_group_in;
+
+	if (data->adc_num > 3)
+		data->groups[num_attr_groups++] = &imanager_group_other;
+
+	if (data->fan_num)
+		data->groups[num_attr_groups++] = &imanager_group_fan;
+
+	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
+				"imanager_hwmon", data, data->groups);
+
+	return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct platform_driver imanager_hwmon_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name  = "imanager_hwmon",
+	},
+	.probe	= imanager_hwmon_probe,
+};
+
+module_platform_driver(imanager_hwmon_driver);
+
+MODULE_DESCRIPTION("Advantech iManager HWmon Driver");
+MODULE_AUTHOR("Richard Vidal-Dorsch <richard.dorsch at advantech.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imanager_hwmon");
diff --git a/include/linux/mfd/imanager/hwmon.h b/include/linux/mfd/imanager/hwmon.h
new file mode 100644
index 0000000..2a7e191
--- /dev/null
+++ b/include/linux/mfd/imanager/hwmon.h
@@ -0,0 +1,120 @@
+/*
+ * Advantech iManager Hardware Monitoring core
+ *
+ * Copyright (C) 2016 Advantech Co., Ltd., Irvine, CA, USA
+ * Author: Richard Vidal-Dorsch <richard.dorsch@advantech.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __HWMON_H__
+#define __HWMON_H__
+
+#include <linux/types.h>
+
+#define HWM_MAX_ADC	5
+#define HWM_MAX_FAN	3
+
+/* Voltage computation (10-bit ADC, 0..3V input) */
+#define SCALE_IN	2933	/* (3000mV / (2^10 - 1)) * 1000 */
+
+/* Default Voltage Sensors */
+struct hwm_voltage {
+	bool valid;	/* if set, below values are valid */
+
+	int value;
+	int min;
+	int max;
+	int average;
+	int lowest;
+	int highest;
+
+};
+
+struct hwm_fan_temp_limit {
+	int stop;
+	int min;
+	int max;
+};
+
+struct hwm_fan_limit {
+	int min;
+	int max;
+};
+
+struct hwm_fan_alert {
+	int min;
+	int max;
+	int min_alarm;
+	int max_alarm;
+};
+
+struct hwm_sensors_limit {
+	struct hwm_fan_temp_limit temp;
+	struct hwm_fan_limit	  pwm;
+	struct hwm_fan_limit	  rpm;
+};
+
+struct hwm_smartfan {
+	bool valid;	/* if set, below values are valid */
+
+	int mode;
+	int type;
+	int pwm;
+	int speed;
+	int pulse;
+	int alarm;
+	int temp;
+
+	struct hwm_sensors_limit limit;
+	struct hwm_fan_alert	 alert;
+};
+
+struct hwm_data {
+	struct hwm_voltage	volt[HWM_MAX_ADC];
+	struct hwm_smartfan	fan[HWM_MAX_FAN];
+};
+
+enum fan_unit {
+	FAN_CPU,
+	FAN_SYS1,
+	FAN_SYS2,
+};
+
+enum fan_ctrl_type {
+	CTRL_PWM,
+	CTRL_RPM,
+};
+
+enum fan_mode {
+	MODE_OFF,
+	MODE_FULL,
+	MODE_MANUAL,
+	MODE_AUTO,
+};
+
+int hwm_core_init(void);
+
+int hwm_core_adc_is_available(int num);
+int hwm_core_adc_get_max_count(void);
+int hwm_core_adc_get_value(int num, struct hwm_voltage *volt);
+const char *hwm_core_adc_get_label(int num);
+
+int hwm_core_fan_is_available(int num);
+int hwm_core_fan_get_max_count(void);
+int hwm_core_fan_get_ctrl(int num, struct hwm_smartfan *fan);
+int hwm_core_fan_set_ctrl(int num, int fmode, int ftype, int pwm, int pulse,
+			  struct hwm_sensors_limit *limit,
+			  struct hwm_fan_alert *alert);
+
+int hwm_core_fan_set_rpm_limit(int num, int min, int max);
+int hwm_core_fan_set_pwm_limit(int num, int min, int max);
+int hwm_core_fan_set_temp_limit(int num, int stop, int min, int max);
+
+const char *hwm_core_fan_get_label(int num);
+const char *hwm_core_fan_get_temp_label(int num);
+
+#endif
-- 
2.6.4


^ permalink raw reply related	[flat|nested] 43+ messages in thread
[parent not found: <201906240241.S3kwAGar%lkp@intel.com>]
* [nomadik:ixp4 4/9] drivers/gpio/gw_i2c_pld.c:25:10: fatal error: linux/i2c/gw_i2c_pld.h: No such file or directory
@ 2018-12-30  5:10 kbuild test robot
  2018-12-30  5:10 ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2018-12-30  5:10 UTC (permalink / raw)
  To: Linus Walleij; +Cc: kbuild-all, linux-arm-kernel

[-- Attachment #1: Type: text/plain, Size: 1252 bytes --]

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git ixp4
head:   fd04bd59327ab42cfa79c1a5aaa3160fc4821402
commit: 443f1c782cc742e40a1ef4cb2bca0afa2fea9baf [4/9] GW i2c PLF GPIO
config: i386-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
        git checkout 443f1c782cc742e40a1ef4cb2bca0afa2fea9baf
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

>> drivers/gpio/gw_i2c_pld.c:25:10: fatal error: linux/i2c/gw_i2c_pld.h: No such file or directory
    #include <linux/i2c/gw_i2c_pld.h>
             ^~~~~~~~~~~~~~~~~~~~~~~~
   compilation terminated.

coccinelle warnings: (new ones prefixed by >>)

>> drivers/gpio/gw_i2c_pld.c:351:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

vim +25 drivers/gpio/gw_i2c_pld.c

  > 25	#include <linux/i2c/gw_i2c_pld.h>
    26	#include <linux/module.h>
    27	#include <linux/export.h>
    28	#include <asm/gpio.h>
    29	#include <mach/hardware.h>
    30	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 66063 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH 1/2] add driver for cypress cy8cmbr3102
  2017-02-20 10:33 ` Patrick Vogelaar
@ 2017-02-20 12:05 kbuild test robot
  2017-02-20 10:33 ` Patrick Vogelaar
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2017-02-20 12:05 UTC (permalink / raw)
  To: Patrick Vogelaar
  Cc: kbuild-all, dmitry.torokhov, linux-kernel, devicetree,
	linux-input, Patrick Vogelaar

Hi Patrick,

[auto build test WARNING on input/next]
[also build test WARNING on v4.10 next-20170220]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Patrick-Vogelaar/add-driver-for-cypress-cy8cmbr3102/20170220-185014
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/input/misc/cy8cmbr3102.c:210:4-9: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH] ALSA SoC MAX98927 driver - Initial release
  2016-11-23  4:57 ` Ryan Lee
@ 2016-11-23 18:13 kbuild test robot
  2016-11-23  4:57 ` Ryan Lee
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-11-23 18:13 UTC (permalink / raw)
  To: Ryan Lee
  Cc: kbuild-all, lgirdwood, broonie, robh+dt, mark.rutland, perex,
	tiwai, arnd, michael, oder_chiou, yesanishhere, jacob,
	Damien.Horsley, bardliao, kuninori.morimoto.gx, petr, lars, nh6z,
	ryans.lee, alsa-devel, devicetree, linux-kernel

Hi Ryan,

[auto build test WARNING on asoc/for-next]
[also build test WARNING on v4.9-rc6 next-20161123]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Ryan-Lee/ALSA-SoC-MAX98927-driver-Initial-release/20161124-004840
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next


coccinelle warnings: (new ones prefixed by >>)

>> sound/soc/codecs/max98927.c:941:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH] This patch allows the Terratec Cinergy HTC Stick HD (0ccb:0101) to be used to watch DVB-T.
  2016-08-06 15:03 ` Gerard H. Pille
@ 2016-08-06 22:00 kbuild test robot
  2016-08-06 15:03 ` Gerard H. Pille
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-08-06 22:00 UTC (permalink / raw)
  To: Gerard H. Pille; +Cc: kbuild-all, linux-media, Gerard H. Pille

Hi Gerard,

[auto build test WARNING on linuxtv-media/master]
[also build test WARNING on v4.7 next-20160805]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Gerard-H-Pille/This-patch-allows-the-Terratec-Cinergy-HTC-Stick-HD-0ccb-0101-to-be-used-to-watch-DVB-T/20160807-042525
base:   git://linuxtv.org/media_tree.git master


coccinelle warnings: (new ones prefixed by >>)

>> drivers/media/dvb-frontends/si2165.c:1192:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* [PATCH] fix platform_no_drv_owner.cocci warnings
@ 2016-07-27 14:41 ` Julia Lawall
  0 siblings, 0 replies; 43+ messages in thread
From: Julia Lawall @ 2016-07-27 14:41 UTC (permalink / raw)
  To: Michal Simek, Dan Williams, Vinod Koul, Sören Brinkmann, Hyun Kwon
  Cc: kbuild-all, linux-arm-kernel, dmaengine, linux-kernel

No need to set .owner here. The core will do it.

Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci

Signed-off-by: Julia Lawall <julia.lawall@lip6.fr>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 xilinx_dpdma.c |    1 -
 1 file changed, 1 deletion(-)

--- a/drivers/dma/xilinx/xilinx_dpdma.c
+++ b/drivers/dma/xilinx/xilinx_dpdma.c
@@ -1944,7 +1944,6 @@ static struct platform_driver xilinx_dpd
 	.remove			= xilinx_dpdma_remove,
 	.driver			= {
 		.name		= "xilinx-dpdma",
-		.owner		= THIS_MODULE,
 		.of_match_table	= xilinx_dpdma_of_match,
 	},
 };

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [media 7/7] PCI bridge driver for PT3 & PXQ3PE
  2016-02-15  6:08 ` info
@ 2016-02-15  7:34 kbuild test robot
  2016-02-15  6:08 ` info
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-02-15  7:34 UTC (permalink / raw)
  To: info
  Cc: kbuild-all, linux-media,
	Буди
	Романто,
	AreMa Inc, linux-kernel, crope, m.chehab, mchehab, hdegoede,
	laurent.pinchart, mkrufky, sylvester.nawrocki, g.liakhovetski,
	peter.senna

[-- Attachment #1: Type: text/plain, Size: 3131 bytes --]

Hi Буди,

[auto build test ERROR on linuxtv-media/master]
[cannot apply to v4.5-rc4 next-20160212]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/info-are-ma/Driver-bundle-for-PT3-PX-Q3PE/20160215-141501
base:   git://linuxtv.org/media_tree.git master
config: i386-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All error/warnings (new ones prefixed by >>):

   In file included from drivers/media/pci/ptx/pt3_pci.c:19:0:
>> drivers/media/pci/ptx/ptx_common.h:24:2: error: unknown type name 'fe_delivery_system_t'
     fe_delivery_system_t type;
     ^
--
   In file included from drivers/media/pci/ptx/ptx_common.c:9:0:
>> drivers/media/pci/ptx/ptx_common.h:24:2: error: unknown type name 'fe_delivery_system_t'
     fe_delivery_system_t type;
     ^
   drivers/media/pci/ptx/ptx_common.c: In function 'ptx_abort':
>> drivers/media/pci/ptx/ptx_common.c:199:6: error: implicit declaration of function 'vzalloc' [-Werror=implicit-function-declaration]
     s = vzalloc(slen);
         ^
>> drivers/media/pci/ptx/ptx_common.c:199:4: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
     s = vzalloc(slen);
       ^
>> drivers/media/pci/ptx/ptx_common.c:203:3: error: implicit declaration of function 'vfree' [-Werror=implicit-function-declaration]
      vfree(s);
      ^
   cc1: some warnings being treated as errors
--
   In file included from drivers/media/pci/ptx/pxq3pe_pci.c:18:0:
>> drivers/media/pci/ptx/ptx_common.h:24:2: error: unknown type name 'fe_delivery_system_t'
     fe_delivery_system_t type;
     ^
   drivers/media/pci/ptx/pxq3pe_pci.c: In function 'pxq3pe_remove':
>> drivers/media/pci/ptx/pxq3pe_pci.c:499:3: error: implicit declaration of function 'vfree' [-Werror=implicit-function-declaration]
      vfree(p->sBuf);
      ^
   drivers/media/pci/ptx/pxq3pe_pci.c: In function 'pxq3pe_probe':
>> drivers/media/pci/ptx/pxq3pe_pci.c:552:14: error: implicit declaration of function 'vzalloc' [-Werror=implicit-function-declaration]
      p->sBuf  = vzalloc(p->sBufSize);
                 ^
>> drivers/media/pci/ptx/pxq3pe_pci.c:552:12: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
      p->sBuf  = vzalloc(p->sBufSize);
               ^
   cc1: some warnings being treated as errors

coccinelle warnings: (new ones prefixed by >>)

>> drivers/media/dvb-frontends/tc90522.c:271:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

vim +/fe_delivery_system_t +24 drivers/media/pci/ptx/ptx_common.h

    18	enum ePTX {
    19		PTX_TS_SYNC	= 0x47,
    20		PTX_TS_NOT_SYNC	= 0x74,
    21	};
    22	
    23	struct ptx_subdev_info {
  > 24		fe_delivery_system_t	type;
    25		u8	demod_addr,	*demod_name,
    26			tuner_addr,	*tuner_name;
    27	};

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 53467 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH v2 5/6] Add Advantech iManager Backlight driver
@ 2016-01-10 10:44 kbuild test robot
       [not found] ` <1452417098-28667-1-git-send-email-richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-01-10 10:44 UTC (permalink / raw)
  Cc: kbuild-all, linux-kernel, lm-sensors, linux-i2c, linux-watchdog,
	linux-gpio, lee.jones, jdelvare, linux, wim, jo.sunga,
	Richard Vidal-Dorsch

Hi Richard,

[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.4-rc8 next-20160108]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/richard-dorsch-gmail-com/Add-Advantech-iManager-EC-driver-set/20160110-171635
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/video/backlight/imanager-bl.c:187:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH v2 4/6] Add Advantech iManager I2C driver
  2016-01-10  9:11 ` richard.dorsch
@ 2016-01-10 10:34 kbuild test robot
  2016-01-10  9:11 ` richard.dorsch
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-01-10 10:34 UTC (permalink / raw)
  Cc: kbuild-all, linux-kernel, lm-sensors, linux-i2c, linux-watchdog,
	linux-gpio, lee.jones, jdelvare, linux, wim, jo.sunga,
	Richard Vidal-Dorsch

Hi Richard,

[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.4-rc8 next-20160108]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/richard-dorsch-gmail-com/Add-Advantech-iManager-EC-driver-set/20160110-171635
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/i2c/busses/imanager-i2c.c:228:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH v2 1/6] Add Advantech iManager MFD core driver
  2016-01-10  9:10 ` richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w
@ 2016-01-10 10:11 kbuild test robot
  2016-01-10  9:10 ` richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-01-10 10:11 UTC (permalink / raw)
  Cc: kbuild-all, linux-kernel, lm-sensors, linux-i2c, linux-watchdog,
	linux-gpio, lee.jones, jdelvare, linux, wim, jo.sunga,
	Richard Vidal-Dorsch

Hi Richard,

[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.4-rc8 next-20160108]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/richard-dorsch-gmail-com/Add-Advantech-iManager-EC-driver-set/20160110-171635
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/mfd/imanager-core.c:248:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH 6/6] Add Advantech iManager Watchdog driver
@ 2016-01-09  2:02 kbuild test robot
       [not found] ` <1452292166-20118-7-git-send-email-richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-01-09  2:02 UTC (permalink / raw)
  Cc: kbuild-all, linux-kernel, lm-sensors, linux-i2c, linux-watchdog,
	linux-gpio, lee.jones, jdelvare, linux, wim, jo.sunga,
	Richard Vidal-Dorsch

Hi Richard,

[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.4-rc8 next-20160108]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/richard-dorsch-gmail-com/Add-Advantech-iManager-EC-driver-set/20160109-063329
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/watchdog/imanager-wdt.c:322:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH 2/6] Add Advantech iManager GPIO driver
  2016-01-08 22:29 ` richard.dorsch
@ 2016-01-09  0:50 kbuild test robot
  2016-01-08 22:29 ` richard.dorsch
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2016-01-09  0:50 UTC (permalink / raw)
  Cc: kbuild-all, linux-kernel, lm-sensors, linux-i2c, linux-watchdog,
	linux-gpio, lee.jones, jdelvare, linux, wim, jo.sunga,
	Richard Vidal-Dorsch

Hi Richard,

[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.4-rc8 next-20160108]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/richard-dorsch-gmail-com/Add-Advantech-iManager-EC-driver-set/20160109-063329
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next


coccinelle warnings: (new ones prefixed by >>)

>> drivers/gpio/imanager-gpio.c:170:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 43+ messages in thread
* Re: [PATCH] add new platform driver for PCI RC
  2015-11-13 12:06 ` [PATCHv3] " Joao Pinto
@ 2015-11-13 11:36 kbuild test robot
  2015-11-13 12:06 ` [PATCHv3] " Joao Pinto
  0 siblings, 1 reply; 43+ messages in thread
From: kbuild test robot @ 2015-11-13 11:36 UTC (permalink / raw)
  To: Joao Pinto; +Cc: kbuild-all, bhelgaas, CARLOS.PALMINHA, linux-pci, Joao Pinto

[-- Attachment #1: Type: text/plain, Size: 13645 bytes --]

Hi Joao,

[auto build test ERROR on: v4.3-rc7]
[cannot apply to: pci/next next-20151113]

url:    https://github.com/0day-ci/linux/commits/Joao-Pinto/add-new-platform-driver-for-PCI-RC/20151113-190212
config: i386-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   drivers/pci/host/pcie-designware.c:76:52: warning: 'struct pci_sys_data' declared inside parameter list
    static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
                                                       ^
   drivers/pci/host/pcie-designware.c:76:52: warning: its scope is only this definition or declaration, which is probably not what you want
   In file included from include/uapi/linux/stddef.h:1:0,
                    from include/linux/stddef.h:4,
                    from include/uapi/linux/posix_types.h:4,
                    from include/uapi/linux/types.h:13,
                    from include/linux/types.h:5,
                    from include/linux/smp.h:10,
                    from include/linux/irq.h:12,
                    from drivers/pci/host/pcie-designware.c:14:
   drivers/pci/host/pcie-designware.c: In function 'sys_to_pcie':
>> drivers/pci/host/pcie-designware.c:78:13: error: dereferencing pointer to incomplete type 'struct pci_sys_data'
     BUG_ON(!sys->private_data);
                ^
   include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
    # define unlikely(x) __builtin_expect(!!(x), 0)
                                             ^
   drivers/pci/host/pcie-designware.c:78:2: note: in expansion of macro 'BUG_ON'
     BUG_ON(!sys->private_data);
     ^
   drivers/pci/host/pcie-designware.c: In function 'dw_pcie_host_init':
   drivers/pci/host/pcie-designware.c:530:2: error: invalid use of undefined type 'struct hw_pci'
     dw_pci.nr_controllers = 1;
     ^
   drivers/pci/host/pcie-designware.c:531:2: error: invalid use of undefined type 'struct hw_pci'
     dw_pci.private_data = (void **)&pp;
     ^
   drivers/pci/host/pcie-designware.c:533:2: error: implicit declaration of function 'pci_common_init_dev' [-Werror=implicit-function-declaration]
     pci_common_init_dev(pp->dev, &dw_pci);
     ^
   drivers/pci/host/pcie-designware.c: At top level:
   drivers/pci/host/pcie-designware.c:682:41: warning: 'struct pci_sys_data' declared inside parameter list
    static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
                                            ^
   drivers/pci/host/pcie-designware.c: In function 'dw_pcie_setup':
   drivers/pci/host/pcie-designware.c:686:19: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [-Wincompatible-pointer-types]
     pp = sys_to_pcie(sys);
                      ^
   drivers/pci/host/pcie-designware.c:76:33: note: expected 'struct pci_sys_data *' but argument is of type 'struct pci_sys_data *'
    static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
                                    ^
>> drivers/pci/host/pcie-designware.c:688:25: error: 'SZ_1M' undeclared (first use in this function)
     if (global_io_offset < SZ_1M && pp->io_size > 0) {
                            ^
   drivers/pci/host/pcie-designware.c:688:25: note: each undeclared identifier is reported only once for each function it appears in
   drivers/pci/host/pcie-designware.c:689:6: error: dereferencing pointer to incomplete type 'struct pci_sys_data'
      sys->io_offset = global_io_offset - pp->io_bus_addr;
         ^
   drivers/pci/host/pcie-designware.c:690:3: error: implicit declaration of function 'pci_ioremap_io' [-Werror=implicit-function-declaration]
      pci_ioremap_io(global_io_offset, pp->io_base);
      ^
>> drivers/pci/host/pcie-designware.c:691:23: error: 'SZ_64K' undeclared (first use in this function)
      global_io_offset += SZ_64K;
                          ^
   drivers/pci/host/pcie-designware.c: At top level:
   drivers/pci/host/pcie-designware.c:703:56: warning: 'struct pci_sys_data' declared inside parameter list
    static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
                                                           ^
   drivers/pci/host/pcie-designware.c: In function 'dw_pcie_scan_bus':
   drivers/pci/host/pcie-designware.c:706:37: warning: passing argument 1 of 'sys_to_pcie' from incompatible pointer type [-Wincompatible-pointer-types]
     struct pcie_port *pp = sys_to_pcie(sys);
                                        ^
   drivers/pci/host/pcie-designware.c:76:33: note: expected 'struct pci_sys_data *' but argument is of type 'struct pci_sys_data *'
    static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
                                    ^
   drivers/pci/host/pcie-designware.c:708:23: error: dereferencing pointer to incomplete type 'struct pci_sys_data'
     pp->root_bus_nr = sys->busnr;
                          ^
   drivers/pci/host/pcie-designware.c: At top level:
   drivers/pci/host/pcie-designware.c:739:15: error: variable 'dw_pci' has initializer but incomplete type
    static struct hw_pci dw_pci = {
                  ^
   drivers/pci/host/pcie-designware.c:740:2: error: unknown field 'setup' specified in initializer
     .setup  = dw_pcie_setup,
     ^
   drivers/pci/host/pcie-designware.c:740:12: warning: excess elements in struct initializer
     .setup  = dw_pcie_setup,
               ^
   drivers/pci/host/pcie-designware.c:740:12: note: (near initialization for 'dw_pci')
   drivers/pci/host/pcie-designware.c:741:2: error: unknown field 'scan' specified in initializer
     .scan  = dw_pcie_scan_bus,
     ^
   drivers/pci/host/pcie-designware.c:741:11: warning: excess elements in struct initializer
     .scan  = dw_pcie_scan_bus,
              ^
   drivers/pci/host/pcie-designware.c:741:11: note: (near initialization for 'dw_pci')
   drivers/pci/host/pcie-designware.c:742:2: error: unknown field 'map_irq' specified in initializer
     .map_irq = dw_pcie_map_irq,
     ^
   drivers/pci/host/pcie-designware.c:742:13: warning: excess elements in struct initializer
     .map_irq = dw_pcie_map_irq,
                ^
   drivers/pci/host/pcie-designware.c:742:13: note: (near initialization for 'dw_pci')
   drivers/pci/host/pcie-designware.c: In function 'sys_to_pcie':
   drivers/pci/host/pcie-designware.c:81:1: warning: control reaches end of non-void function [-Wreturn-type]
    }
    ^
   cc1: some warnings being treated as errors
--
   drivers/pci/host/pcie-snpsdev.c: In function 'snpsdev_pcie_host_init':
>> drivers/pci/host/pcie-snpsdev.c:139:2: error: implicit declaration of function 'dw_pcie_link_retrain' [-Werror=implicit-function-declaration]
     dw_pcie_link_retrain(pp);
     ^
   cc1: some warnings being treated as errors

coccinelle warnings: (new ones prefixed by >>)

>> drivers/pci/host/pcie-designware.c:158:23-47: Move constant to right.
--
>> drivers/pci/host/pcie-snpsdev.c:323:3-8: No need to set .owner here. The core will do it.

Please review and possibly fold the followup patch.

vim +/dw_pcie_link_retrain +139 drivers/pci/host/pcie-snpsdev.c

   133		snpsdev_pcie_deassert_core_reset(pp);
   134	 
   135		/*We expect the PCIE Link to be up by this time*/
   136		dw_pcie_setup_rc(pp);
   137		
   138		/*Start LTSSM here*/
 > 139		dw_pcie_link_retrain(pp);
   140	
   141		/* Check for Link up indication */
   142		while (!dw_pcie_link_up(pp)) {
   143			usleep_range(1000,1100);
   144			count++;
   145			if (count == 20) {
   146				dev_err(pp->dev, "phy link never came up\n");
   147				dev_dbg(pp->dev,
   148					"PL_DEBUG0: 0x%08x, DEBUG_R1: 0x%08x\n",
   149					readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
   150					readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
   151				break;
   152			}
   153		}
   154	
   155		if (IS_ENABLED(CONFIG_PCI_MSI))
   156			dw_pcie_msi_init(pp);
   157	
   158		return;
   159	}
   160	/**
   161	 *
   162	 * Let all outof band signalling be handled by cfg_phy_control[31:0]
   163	 * which is selected through optional config attribute PHY_CONTROL_REG
   164	 *
   165	 * Monitor cxpl_debug_info as required to take necessary action
   166	 * This is available in the register PCIE_PHY_DEBUG_R0 & PCIE_PHY_DEBUG_R1
   167	 *
   168	 */ 
   169	static int snpsdev_pcie_link_up(struct pcie_port *pp)
   170	{
   171		u32 status;
   172	
   173		/* Bit number 36: reports LTSSM PHY Link UP; Available in bit 3 of
   174	         *  PCIE_PHY_DEBUG_R1 */
   175		status = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << 4);
   176		if(status != 0)
   177			return 1;
   178	
   179		/* TODO: Now Link is in L0; Initiate GEN2/GEN3 migration if RC Supports */
   180		return 0;
   181	}
   182	
   183	
   184	/**
   185	 * This is RC operation structure
   186	 * snpsdev_pcie_link_up: the function which initiates the phy link up procedure
   187	 * snpsdev_pcie_host_init: the function whihc does the host/RC Root port initialization
   188	 */ 
   189	static struct pcie_host_ops snpsdev_pcie_host_ops = {
   190		.link_up = snpsdev_pcie_link_up,
   191		.host_init = snpsdev_pcie_host_init,
   192	};
   193	
   194	/**
   195	 * snpsdev_add_pcie_port
   196	 * This function 
   197	 * a. installs the interrupt handler
   198	 * b. registers host operations int he pcie_port structure
   199	 */ 
   200	static int snpsdev_add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
   201	{
   202		int ret;
   203	
   204		pp->irq = platform_get_irq(pdev, 1);
   205	
   206		if (pp->irq < 0) {
   207			if (pp->irq != -EPROBE_DEFER)
   208				dev_err(&pdev->dev, "cannot get irq\n");
   209			return pp->irq;
   210		}
   211	
   212		ret = devm_request_irq(&pdev->dev, pp->irq, snpsdev_pcie_irq_handler,
   213					IRQF_SHARED, "snpsdev-pcie", pp);
   214	
   215		if (ret) {
   216			dev_err(&pdev->dev, "failed to request irq\n");
   217			return ret;
   218		}
   219	
   220		if (IS_ENABLED(CONFIG_PCI_MSI)) {
   221			pp->msi_irq = platform_get_irq(pdev, 0);
   222	
   223			if (pp->msi_irq < 0) {
   224				if (pp->msi_irq != -EPROBE_DEFER)
   225					dev_err(&pdev->dev, "cannot get msi irq\n");
   226				return pp->msi_irq;
   227			}
   228	
   229			ret = devm_request_irq(&pdev->dev, pp->msi_irq,
   230						snpsdev_pcie_msi_irq_handler,
   231						IRQF_SHARED, "snpsdev-pcie-msi", pp);
   232			if (ret) {
   233				dev_err(&pdev->dev, "failed to request msi irq\n");
   234				return ret;
   235			}
   236		}
   237	
   238		pp->root_bus_nr = -1;
   239		pp->ops = &snpsdev_pcie_host_ops;
   240	
   241		/* Below function: 
   242	 	 * Checks for range property from DT
   243	 	 * Gets the IO and MEMORY and CONFIG-Space ranges from DT
   244	 	 * Does IOREMAPS on the physical addresses 
   245	 	 * Gets the num-lanes from DT
   246	 	 * Gets MSI capability from DT
   247	 	 * Calls the platform specific host initialization
   248	 	 * Program the correct class, BAR0, Link width,  in Config space
   249	 	 * Then it calls pci common init routine
   250	 	 * Then it calls funtion to assign "unassigend reources"
   251	         */
   252		ret = dw_pcie_host_init(pp);
   253		if (ret) {
   254			dev_err(&pdev->dev, "failed to initialize host\n");
   255			return ret;
   256		}
   257	
   258		return 0;
   259	}
   260	
   261	/**
   262	 * snpsdev_pcie_rc_probe()
   263	 * This function gets called as part of pcie registration. if the id matches
   264	 * the platform driver framework will call this function.
   265	 *
   266	 * @pdev: Pointer to the platform_device structure
   267	 *
   268	 * Returns zero on success; Negative errorno on failure
   269	 */
   270	static int __init snpsdev_pcie_rc_probe(struct platform_device *pdev)
   271	{
   272		struct snpsdev_pcie *snpsdev_pcie;
   273		struct pcie_port *pp;
   274		struct resource *dwc_pcie_rc_res;  /* Resource from DT */
   275		int ret;
   276	
   277		snpsdev_pcie = devm_kzalloc(&pdev->dev, sizeof(*snpsdev_pcie), GFP_KERNEL);
   278		if (!snpsdev_pcie) {
   279			dev_err(&pdev->dev, "no memory for snpsdev pcie\n");
   280			return -ENOMEM;
   281		}
   282	
   283		pp = &snpsdev_pcie->pp;
   284		pp->dev = &pdev->dev;
   285	
   286		dwc_pcie_rc_res= platform_get_resource(pdev, IORESOURCE_MEM, 0);
   287		if (!dwc_pcie_rc_res) {
   288			dev_err(&pdev->dev, "dwc_pcie_rc_res resource not found\n");
   289			return -ENODEV;
   290		}
   291	
   292		snpsdev_pcie->mem_base = devm_ioremap_resource(&pdev->dev, dwc_pcie_rc_res);
   293		if (IS_ERR(snpsdev_pcie->mem_base)) {
   294			ret = PTR_ERR(snpsdev_pcie->mem_base);
   295			return ret;
   296		}
   297		pp->dbi_base = snpsdev_pcie->mem_base;	
   298	
   299		ret = snpsdev_add_pcie_port(pp, pdev);
   300		if (ret < 0)
   301			return ret;
   302	
   303		platform_set_drvdata(pdev, snpsdev_pcie);
   304	
   305		return 0;
   306	}
   307	
   308	static int __exit snpsdev_pcie_rc_remove(struct platform_device *pdev)
   309	{
   310		return 0;
   311	}
   312	
   313	static const struct of_device_id snpsdev_pcie_rc_of_match[] = {
   314		{ .compatible = "snps,pcie-snpsdev", },
   315		{},
   316	};
   317	MODULE_DEVICE_TABLE(of, snpsdev_pcie_rc_of_match);
   318	
   319	static struct platform_driver snpsdev_pcie_rc_driver = {
   320		.remove		= __exit_p(snpsdev_pcie_rc_remove),
   321		.driver = {
   322			.name	= "pcie-snpsdev",
 > 323			.owner	= THIS_MODULE,
   324			.of_match_table = snpsdev_pcie_rc_of_match,
   325		},
   326	};

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 51602 bytes --]

^ permalink raw reply	[flat|nested] 43+ messages in thread
[parent not found: <201503291519.K9Z6Qptb%fengguang.wu@intel.com>]
[parent not found: <201503291545.My1tADgz%fengguang.wu@intel.com>]
[parent not found: <201503291531.GP28FwKy%fengguang.wu@intel.com>]
[parent not found: <201502131224.TGzEj1Ve%fengguang.wu@intel.com>]
[parent not found: <201501160912.S502Nlmz%fengguang.wu@intel.com>]

end of thread, other threads:[~2019-06-23 18:50 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-10  9:11 [PATCH v2 3/6] Add Advantech iManager HWmon driver richard.dorsch
2016-01-10 10:25 ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-10 10:25   ` kbuild test robot
2016-01-10 10:25 ` [PATCH v2 3/6] Add Advantech iManager HWmon driver kbuild test robot
2016-01-10 10:25   ` kbuild test robot
     [not found] <201906240241.S3kwAGar%lkp@intel.com>
2019-06-23 18:50 ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
  -- strict thread matches above, loose matches on Subject: below --
2018-12-30  5:10 [nomadik:ixp4 4/9] drivers/gpio/gw_i2c_pld.c:25:10: fatal error: linux/i2c/gw_i2c_pld.h: No such file or directory kbuild test robot
2018-12-30  5:10 ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2017-02-20 12:05 [PATCH 1/2] add driver for cypress cy8cmbr3102 kbuild test robot
2017-02-20 10:33 ` Patrick Vogelaar
2017-02-20 12:05   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2017-02-20 12:05     ` kbuild test robot
2016-11-23 18:13 [PATCH] ALSA SoC MAX98927 driver - Initial release kbuild test robot
2016-11-23  4:57 ` Ryan Lee
2016-11-23 18:13   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-08-06 22:00 [PATCH] This patch allows the Terratec Cinergy HTC Stick HD (0ccb:0101) to be used to watch DVB-T kbuild test robot
2016-08-06 15:03 ` Gerard H. Pille
2016-08-06 22:00   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-07-27 14:41 Julia Lawall
2016-07-27 14:41 ` Julia Lawall
2016-08-08  5:47 ` Vinod Koul
2016-08-08  5:47   ` Vinod Koul
2016-02-15  7:34 [media 7/7] PCI bridge driver for PT3 & PXQ3PE kbuild test robot
2016-02-15  6:08 ` info
2016-02-15  7:34   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-10 10:44 [PATCH v2 5/6] Add Advantech iManager Backlight driver kbuild test robot
     [not found] ` <1452417098-28667-1-git-send-email-richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-01-10 10:44   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-10 10:44     ` kbuild test robot
2016-01-10 10:34 [PATCH v2 4/6] Add Advantech iManager I2C driver kbuild test robot
2016-01-10  9:11 ` richard.dorsch
2016-01-10 10:34   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-10 10:34     ` kbuild test robot
2016-01-10 10:11 [PATCH v2 1/6] Add Advantech iManager MFD core driver kbuild test robot
2016-01-10  9:10 ` richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w
2016-01-10 10:11   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-10 10:11     ` kbuild test robot
2016-01-09  2:02 [PATCH 6/6] Add Advantech iManager Watchdog driver kbuild test robot
     [not found] ` <1452292166-20118-7-git-send-email-richard.dorsch-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-01-09  2:02   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-09  2:02     ` kbuild test robot
2016-01-09  0:50 [PATCH 2/6] Add Advantech iManager GPIO driver kbuild test robot
2016-01-08 22:29 ` richard.dorsch
2016-01-09  0:50   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-09  0:50     ` kbuild test robot
2015-11-13 11:36 [PATCH] add new platform driver for PCI RC kbuild test robot
2015-11-13 12:06 ` [PATCHv3] " Joao Pinto
2015-11-13 11:36   ` [PATCH] fix platform_no_drv_owner.cocci warnings kbuild test robot
     [not found] <201503291519.K9Z6Qptb%fengguang.wu@intel.com>
2015-03-29  7:49 ` kbuild test robot
2015-03-30 13:05   ` Thierry Reding
2015-03-30 13:05     ` Thierry Reding
2015-04-07 13:09     ` Linus Walleij
2015-04-08  1:24       ` Fengguang Wu
     [not found] <201503291545.My1tADgz%fengguang.wu@intel.com>
2015-03-29  7:42 ` kbuild test robot
2015-03-29 16:27   ` Mark Brown
     [not found] <201503291531.GP28FwKy%fengguang.wu@intel.com>
2015-03-29  7:33 ` kbuild test robot
2015-03-29 16:24   ` Mark Brown
2015-03-30 12:52     ` Thierry Reding
     [not found] <201502131224.TGzEj1Ve%fengguang.wu@intel.com>
2015-02-13  4:49 ` kbuild test robot
     [not found] <201501160912.S502Nlmz%fengguang.wu@intel.com>
2015-01-16  1:06 ` kbuild test robot
2015-03-11 11:05   ` Thierry Reding
2015-03-18  1:38     ` Linus Walleij
2015-03-24 10:43       ` Thierry Reding
2015-03-25  1:56         ` Fengguang Wu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.