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>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20130323151556.GB17355@roeck-us.net>
Date:	Sat, 23 Mar 2013 08:15:56 -0700
From:	Guenter Roeck <linux@...ck-us.net>
To:	Wim Van Sebroeck <wim@...ana.be>
Cc:	linux-watchdog@...r.kernel.org, linux-kernel@...r.kernel.org,
	Samuel Ortiz <sameo@...ux.intel.com>,
	Pádraig Brady <P@...igBrady.com>
Subject: mfd: Core driver for W836{2389}7[T]HF

MFD core driver for various variants of Winbond/Nuvoton SuperIO chips.

Signed-off-by: Guenter Roeck <linux@...ck-us.net>
---

My variant of an MFD core driver for Winbond chips.

Key differences to Wim's driver
- Uses mfd infrastructure
- Passes enum instead of raw device id to client drivers
- Uses request_muxed_region instead of an in-module function for
  superio_enter
  [ Using an in-module function and in-module locking may be better ]

TODO:
- Detect and instantiate superio chips on both addresses, not just one.
- Replace static variables 'pdev' and mfd_cells[].

 drivers/mfd/Kconfig          |   22 +++
 drivers/mfd/Makefile         |    1 +
 drivers/mfd/w83627hf-core.c  |  324 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mfd/w83627hf.h |  131 +++++++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 drivers/mfd/w83627hf-core.c
 create mode 100644 include/linux/mfd/w83627hf.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c346941..a141ef6 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1119,6 +1119,28 @@ config MFD_AS3711
 	help
 	  Support for the AS3711 PMIC from AMS
 
+config MFD_W83627HF
+	tristate "Winbond W83627HF and compatibles"
+	select MFD_CORE
+	help
+	  If you say yes here you add support for the Winbond W836X7 and Nuvoton
+	  NCT677X series of super-IO chips. The following chips are supported:
+		W83627F/HF/G/HG/DHG/DHG-P/EHF/EHG/S/SF/THF/UHG/UG
+		W83637HF
+		W83667HG/HG-B
+		W83687THF
+		W83697HF
+		NCT6775
+		NCT6776
+		NCT6779
+
+	  This is a multi functional device and this support defines a new
+	  platform device only. See other configuration submenus in order to
+	  enable the drivers of Winbond chip's functionalities.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83627hf-core.
+
 endmenu
 endif
 
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b90409c..3e9e830 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_MFD_MC13XXX_I2C)	+= mc13xxx-i2c.o
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_MFD_W83627HF)	+= w83627hf-core.o
 
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
diff --git a/drivers/mfd/w83627hf-core.c b/drivers/mfd/w83627hf-core.c
new file mode 100644
index 0000000..d0be5b9
--- /dev/null
+++ b/drivers/mfd/w83627hf-core.c
@@ -0,0 +1,324 @@
+/*
+ *  w83627hf.c - platform device support
+ *
+ *  Copyright (c) 2013 Guenter Roeck <linux@...ck-us.net>
+ *
+ *  Based on earlier work by Rodolfo Giometti
+ *
+ *  Copyright (c) 2009-2011 Rodolfo Giometti <giometti@...ux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@....nl>,
+ *    Philip Edelbrock <phil@...roedge.com>,
+ *    and Mark Studebaker <mdsxyz123@...oo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@...my.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@...ux-fr.org>
+ *
+ *    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.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/w83627hf.h>
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+/*
+ * Devices definitions
+ */
+
+static struct platform_device *pdev;
+
+struct w83627hf_chip_data {
+	const char * const name;
+	const char * const chip;
+	const char * const hwmon_drvname;
+};
+
+static const struct w83627hf_chip_data w83627hf_chip_data[] = {
+	[w83627hf] = {
+		.name = __stringify(w83627hf),
+		.chip = "W83627HF",
+		.hwmon_drvname = W83627HF_HWMON_DRVNAME,
+	},
+	[w83627s] = {
+		.name = __stringify(w83627s),
+		.chip = "W83627S",
+	},
+	[w83627thf] = {
+		.name = __stringify(w83627thf),
+		.chip = "W83627THF",
+		.hwmon_drvname = W83627HF_HWMON_DRVNAME,
+	},
+	[w83697hf] = {
+		.name = __stringify(w83697hf),
+		.chip = "W83697HF",
+		.hwmon_drvname = W83627HF_HWMON_DRVNAME,
+	},
+	[w83697ug] = {
+		.name = __stringify(w83697ug),
+		.chip = "W83697SF/UG",
+	},
+	[w83637hf] = {
+		.name = __stringify(w83637hf),
+		.chip = "W83637HF",
+		.hwmon_drvname = W83627HF_HWMON_DRVNAME,
+	},
+	[w83687thf] = {
+		.name = __stringify(w83687thf),
+		.chip = "W83687THF",
+		.hwmon_drvname = W83627HF_HWMON_DRVNAME,
+	},
+	[w83627ehf] = {
+		.name = __stringify(w83627ehf),
+		.chip = "W83627EHF",
+		.hwmon_drvname = W83627EHF_HWMON_DRVNAME,
+	},
+	[w83627dhg] = {
+		.name = __stringify(w83627dhg),
+		.chip = "W83627DHG",
+		.hwmon_drvname = W83627EHF_HWMON_DRVNAME,
+	},
+	[w83627dhg_p] = {
+		.name = __stringify(w83627dhg),
+		.chip = "W83627DHG-P",
+		.hwmon_drvname = W83627EHF_HWMON_DRVNAME,
+	},
+	[w83627uhg] = {
+		.name = __stringify(w83627uhg),
+		.chip = "W83627UHG",
+		.hwmon_drvname = W83627EHF_HWMON_DRVNAME,
+	},
+	[w83667hg] = {
+		.name = __stringify(w83667hg),
+		.chip = "W83667HG",
+		.hwmon_drvname = W83627EHF_HWMON_DRVNAME,
+	},
+	[w83667hg_b] = {
+		.name = __stringify(w83667hg),
+		.chip = "W83667HG-B",
+		.hwmon_drvname = W83627EHF_HWMON_DRVNAME,
+	},
+	[nct6775] = {
+		.name = __stringify(nct6775),
+		.chip = "NCT6775",
+		.hwmon_drvname = NCT6775_HWMON_DRVNAME,
+	},
+	[nct6776] = {
+		.name = __stringify(nct6776),
+		.chip = "NCT6776",
+		.hwmon_drvname = NCT6775_HWMON_DRVNAME,
+	},
+	[nct6779] = {
+		.name = __stringify(nct6779),
+		.chip = "NCT6779",
+		.hwmon_drvname = NCT6775_HWMON_DRVNAME,
+	},
+};
+
+#define MFD_NUM_CELLS	2
+
+static struct mfd_cell mfd_cells[MFD_NUM_CELLS];
+
+#define W83627HF_CR_DEVID	0x20
+
+#define W83627HF_G_DEVID	0x5210
+#define W83627HF_J_DEVID	0x5230
+#define W83627HF_UD_DEVID	0x5240
+#define W83627S_DEVID		0x5950
+#define W83627THF_DEVID		0x8280
+#define W83697HF_DEVID		0x6010
+#define W83697SF_DEVID		0x6800
+#define W83697UG_DEVID		0x6810
+#define W83637HF_DEVID		0x7080
+#define W83687THF_DEVID		0x8540
+#define W83627EHF_DEVID		0x8850
+#define W83627EHG_DEVID		0x8860
+#define W83627DHG_DEVID		0xa020
+#define W83627DHG_P_DEVID	0xb070
+#define W83627UHG_DEVID		0xa230
+#define W83667HG_DEVID		0xa510
+#define W83667HG_B_DEVID	0xb350
+#define NCT6775_DEVID		0xb470
+#define NCT6776_DEVID		0xc330
+#define NCT6779_DEVID		0xc560
+
+#define DEVID_MASK		0xfff0
+
+static int __init w83627hf_find(int sioaddr,
+				struct w83627hf_platform_data *pdata)
+{
+	int err = 0;
+	u16 val;
+
+	err = superio_enter(sioaddr);
+	if (err)
+		return err;
+
+	val = force_id ? : ((superio_inb(sioaddr, W83627HF_CR_DEVID) << 8) |
+			    superio_inb(sioaddr, W83627HF_CR_DEVID + 1));
+
+	switch (val & DEVID_MASK) {
+	case W83627HF_G_DEVID:
+	case W83627HF_J_DEVID:
+	case W83627HF_UD_DEVID:
+		pdata->type = w83627hf;
+		break;
+	case W83627S_DEVID:
+		pdata->type = w83627s;
+		break;
+	case W83627THF_DEVID:
+		pdata->type = w83627thf;
+		break;
+	case W83697HF_DEVID:
+		pdata->type = w83697hf;
+		break;
+	case W83697SF_DEVID:
+	case W83697UG_DEVID:
+		pdata->type = w83697ug;
+		break;
+	case W83637HF_DEVID:
+		pdata->type = w83637hf;
+		break;
+	case W83687THF_DEVID:
+		pdata->type = w83687thf;
+		break;
+	case W83627EHF_DEVID:
+	case W83627EHG_DEVID:
+		pdata->type = w83627ehf;
+		break;
+	case W83627DHG_DEVID:
+		pdata->type = w83627dhg;
+		break;
+	case W83627DHG_P_DEVID:
+		pdata->type = w83627dhg_p;
+		break;
+	case W83627UHG_DEVID:
+		pdata->type = w83627uhg;
+		break;
+	case W83667HG_DEVID:
+		pdata->type = w83667hg;
+		break;
+	case W83667HG_B_DEVID:
+		pdata->type = w83667hg_b;
+		break;
+	case NCT6775_DEVID:
+		pdata->type = nct6775;
+		break;
+	case NCT6776_DEVID:
+		pdata->type = nct6776;
+		break;
+	case NCT6779_DEVID:
+		pdata->type = nct6779;
+		break;
+	case 0xfff0:	/* No device at all */
+		err = -ENODEV;
+		goto exit;
+	default:
+		err = -ENODEV;
+		pr_debug("Unsupported chip (DEVID=0x%04x)\n", val);
+		goto exit;
+	}
+	pdata->sioaddr = sioaddr;
+	pdata->name = w83627hf_chip_data[pdata->type].name;
+	pr_info("Found %s at %#x\n", w83627hf_chip_data[pdata->type].chip,
+		sioaddr);
+exit:
+	superio_exit(sioaddr);
+	return err;
+}
+
+static int __init w83627hf_device_add(struct w83627hf_platform_data *pdata)
+{
+	int err;
+	int cells = 0;
+
+	pdev = platform_device_alloc(W83627HF_CORE_DRVNAME, 0);
+	if (!pdev)
+		return -ENOMEM;
+
+	err = platform_device_add_data(pdev, pdata,
+				       sizeof(struct w83627hf_platform_data));
+	if (err)
+		goto exit_device_put;
+
+	if (w83627hf_chip_data[pdata->type].hwmon_drvname) {
+		mfd_cells[cells].name =
+		  w83627hf_chip_data[pdata->type].hwmon_drvname;
+		cells++;
+	}
+
+	mfd_cells[cells].name = W83627HF_WDT_DRVNAME;
+	cells++;
+
+	err = platform_device_add(pdev);
+	if (err)
+		goto exit_device_put;
+
+	err = mfd_add_devices(&pdev->dev, pdev->id, mfd_cells, cells,
+			      NULL, -1, NULL);
+	if (err)
+		goto exit_device_unregister;
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(pdev);
+exit_device_put:
+	platform_device_put(pdev);
+	return err;
+}
+
+static int __init w83627hf_init(void)
+{
+	struct w83627hf_platform_data pdata;
+	int ret;
+
+	ret = w83627hf_find(0x2e, &pdata);
+	if (ret) {
+		ret = w83627hf_find(0x4e, &pdata);
+		if (ret)
+			return -ENODEV;
+	}
+
+	/* Sets global pdev as a side effect */
+	return w83627hf_device_add(&pdata);
+}
+
+static void __exit w83627hf_exit(void)
+{
+	mfd_remove_devices(&pdev->dev);
+	platform_device_unregister(pdev);
+}
+
+MODULE_AUTHOR("Guenter Roeck <linux@...ck-us.net>");
+MODULE_DESCRIPTION("W83627HF multi-function core driver");
+MODULE_LICENSE("GPL");
+
+module_init(w83627hf_init);
+module_exit(w83627hf_exit);
diff --git a/include/linux/mfd/w83627hf.h b/include/linux/mfd/w83627hf.h
new file mode 100644
index 0000000..6379126
--- /dev/null
+++ b/include/linux/mfd/w83627hf.h
@@ -0,0 +1,131 @@
+/*
+ *  w83627hf.h - platform device support, header file
+ *  Copyright (c) 2009 Rodolfo Giometti <giometti@...ux.it>
+ *
+ *  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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#define W83627HF_CORE_DRVNAME "w83627hf_core"
+#define W83627HF_HWMON_DRVNAME "w83627hf_hwmon"
+#define W83627EHF_HWMON_DRVNAME "w83627ehf_hwmon"
+#define NCT6775_HWMON_DRVNAME "nct6775_hwmon"
+
+#define W83627HF_WDT_DRVNAME	"w83627hf_wdt"
+
+enum chips {
+	w83627hf,
+	w83627s,
+	w83627thf,
+	w83697hf,
+	w83697ug,
+	w83637hf,
+	w83687thf,
+	w83627ehf,
+	w83627dhg,
+	w83627dhg_p,
+	w83627uhg,
+	w83667hg,
+	w83667hg_b,
+	nct6775,
+	nct6776,
+	nct6779,
+};
+
+struct w83627hf_platform_data {
+	int sioaddr;
+	enum chips type;
+	const char *name;
+};
+
+#define W83627HF_SELECT		0x07
+
+/* logical device numbers for superio_select */
+#define W83627HF_LD_FDC		0x00
+#define W83627HF_LD_PRT		0x01
+#define W83627HF_LD_UART1	0x02
+#define W83627HF_LD_UART2	0x03
+#define W83627HF_LD_KBC		0x05
+#define W83627HF_LD_CIR		0x06 /* w83627hf only */
+#define W83627HF_LD_GAME	0x07
+#define W83627HF_LD_MIDI	0x07
+#define W83627HF_LD_GPIO1	0x07
+#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */
+#define W83627HF_LD_GPIO2	0x08
+#define W83627HF_LD_WDT		0x08
+#define W83627HF_LD_GPIO3	0x09
+#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */
+#define W83627HF_LD_ACPI	0x0a
+#define W83627HF_LD_HWM		0x0b
+
+#define W83627HF_CR_ENABLE	0x30	/* Logical device enable register */
+
+#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */
+#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */
+
+#define W83687THF_VID_EN	0x29 /* w83687thf only */
+#define W83687THF_VID_CFG	0xF0 /* w83687thf only */
+#define W83687THF_VID_DATA	0xF1 /* w83687thf only */
+
+/*
+ * Common configuration registers access functions.
+ *
+ * These registers are special and they must me accessed by using a well
+ * specified protocol. Client drivers __must__ do as follow in order to
+ * get access correctly to these registers:
+ *
+ *	superio_enter()
+ *	superio_select()/superio_outb()/superio_inb()
+ *	suprio_exit();
+ *
+ */
+
+static inline int superio_enter(int sioaddr)
+{
+	if (!request_muxed_region(sioaddr, 2, KBUILD_MODNAME))
+		return -EBUSY;
+
+	outb(0x87, sioaddr);
+	outb(0x87, sioaddr);
+
+	return 0;
+}
+
+static inline void superio_select(int sioaddr, int ld)
+{
+	outb(W83627HF_SELECT, sioaddr);
+	outb(ld, sioaddr + 1);
+}
+
+static inline void superio_outb(int sioaddr, int reg, int val)
+{
+	outb(reg, sioaddr);
+	outb(val, sioaddr + 1);
+}
+
+static inline int superio_inb(int sioaddr, int reg)
+{
+	outb(reg, sioaddr);
+	return inb(sioaddr + 1);
+}
+
+static inline void superio_exit(int sioaddr)
+{
+	outb(0xAA, sioaddr);
+
+	release_region(sioaddr, 2);
+}
-- 
1.7.9.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ