public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Wim Van Sebroeck <wim@iguana.be>
Cc: linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org,
	"Samuel Ortiz" <sameo@linux.intel.com>,
	"Pádraig Brady" <P@draigBrady.com>
Subject: mfd: Core driver for Winbond chips
Date: Sat, 23 Mar 2013 10:49:14 -0700	[thread overview]
Message-ID: <20130323174914.GA21563@roeck-us.net> (raw)
In-Reply-To: <20130323002810.GA26245@roeck-us.net>

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

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
 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@roeck-us.net>
+ *
+ *  Based on earlier work by Rodolfo Giometti
+ *
+ *  Copyright (c) 2009-2011 Rodolfo Giometti <giometti@linux.it>
+ *
+ *  Based on drivers/hwmon/w83627hf.c
+ *
+ *  Original copyright note:
+ *    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,
+ *    Philip Edelbrock <phil@netroedge.com>,
+ *    and Mark Studebaker <mdsxyz123@yahoo.com>
+ *    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ *    Copyright (c) 2007  Jean Delvare <khali@linux-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@roeck-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@linux.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


  parent reply	other threads:[~2013-03-24  2:18 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-03-10 23:14 [PATCH v2 0/8] watchdog: w83627hf: Convert to watchdog infrastructure Guenter Roeck
2013-03-10 23:14 ` [PATCH v2 1/7] " Guenter Roeck
2013-03-10 23:14 ` [PATCH v2 2/7] watchdog: w83627hf: Enable watchdog only once Guenter Roeck
2013-03-19 17:26   ` Pádraig Brady
2013-03-19 20:02     ` Guenter Roeck
2013-03-21 18:40       ` Pádraig Brady
2013-03-10 23:14 ` [PATCH v2 3/7] watchdog: w83627hf: Enable watchdog device only if not already enabled Guenter Roeck
2013-03-10 23:14 ` [PATCH v2 4/7] watchdog: w83627hf: Use helper functions to access superio registers Guenter Roeck
2013-03-10 23:14 ` [PATCH v2 5/7] watchdog: w83627hf: Auto-detect IO address and supported chips Guenter Roeck
2013-03-10 23:14 ` [PATCH v2 6/7] watchdog: w83627hf: Add support for W83697HF and W83697UG Guenter Roeck
2013-03-10 23:15 ` [PATCH v2 7/7] watchdog: Remove drivers " Guenter Roeck
2013-03-22 20:52 ` [PATCH v2 0/8] watchdog: w83627hf: Convert to watchdog infrastructure Wim Van Sebroeck
2013-03-22 21:09   ` [RFC] winbond Super-I/O MFD driver Wim Van Sebroeck
2013-03-23  0:28   ` [PATCH v2 0/8] watchdog: w83627hf: Convert to watchdog infrastructure Guenter Roeck
2013-03-23 12:57     ` Wim Van Sebroeck
2013-03-23 15:01       ` Guenter Roeck
2013-03-23 15:15       ` mfd: Core driver for W836{2389}7[T]HF Guenter Roeck
2013-03-23 17:49     ` Guenter Roeck [this message]
2013-03-24  2:39       ` mfd: Core driver for Winbond chips Guenter Roeck
2013-04-09  9:37       ` Samuel Ortiz
2013-04-09 11:36         ` Guenter Roeck
2013-04-09 11:45           ` Wim Van Sebroeck
2013-04-09 16:18             ` Guenter Roeck
2013-04-09 17:31               ` Wim Van Sebroeck
2013-04-10  0:36                 ` Guenter Roeck
2013-04-10 20:59                   ` Wim Van Sebroeck
2013-04-29 15:00                     ` Guenter Roeck
2013-04-09 11:37         ` Wim Van Sebroeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20130323174914.GA21563@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=P@draigBrady.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=sameo@linux.intel.com \
    --cc=wim@iguana.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox