[PATCH 2/2] [temporal change]

From: Alejandro del Rio
Date: Mon Jan 16 2012 - 03:33:05 EST


[temporal change]


Signed-off-by: Alejandro del Rio <scasbyte@xxxxxxxxx>
---
drivers/gpio/Kconfig | 12 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-w83627hf.c | 492 ++++++++++++++++++++++++++++++++++++++++++
drivers/hwmon/Kconfig | 1 +
4 files changed, 506 insertions(+), 0 deletions(-)
create mode 100644 drivers/gpio/gpio-w83627hf.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 37c4bd1..1ada7ad 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -189,6 +189,18 @@ config GPIO_VX855
additional drivers must be enabled in order to use the
functionality of the device.

+config GPIO_W83627HF
+ tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
+ select MFD_CORE
+ select MFD_W83627HF
+ help
+ If you say yes here you get support for the Winbond W836X7 series
+ of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and
+ W83697HF.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83627hf.
+
comment "I2C GPIO expanders:"

config GPIO_MAX7300
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fa10df6..48979bb 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
+obj-$(CONFIG_GPIO_W83627HF) += gpio-w83627hf.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
diff --git a/drivers/gpio/gpio-w83627hf.c b/drivers/gpio/gpio-w83627hf.c
new file mode 100644
index 0000000..934333e
--- /dev/null
+++ b/drivers/gpio/gpio-w83627hf.c
@@ -0,0 +1,492 @@
+/*
+ * gpio-w83627hf.c - GPIO support for w83627hf chip
+ *
+ * Copyright (c) 2010-2011 Rodolfo Giometti <giometti@xxxxxxxxxxx>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/mfd/w83627hf.h>
+
+/* Constants specified below */
+
+#define W83627HF_LD_GPIO3_MUX 0x29
+#define W83627HF_LD_GPIO1_MUX 0x2a
+#define W83627HF_LD_GPIO2_MUX 0x2b
+
+static const unsigned int ngpio[] = {
+ /* port 1 - port 2 - port 3 */
+ 8 + 8 + 6,
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+struct w83627hf_data {
+ struct gpio_chip chip;
+ struct bitmap {
+ unsigned long status:1;
+ } bit[3 * 8];
+};
+
+/*
+ * Local functions
+ */
+
+static void gpio_mode(struct w83627hf_sio_data *sio,
+ unsigned int bit, unsigned int mode)
+{
+ u8 val;
+
+ val = superio_inb(sio, 0xf0);
+ if (mode == 0)
+ val &= ~(1 << bit);
+ else
+ val |= (1 << bit);
+ superio_outb(sio, 0xf0, val);
+}
+
+static int gpio_get(struct w83627hf_sio_data *sio, unsigned int bit)
+{
+ u8 val;
+
+ val = superio_inb(sio, 0xf1);
+ val &= (1 << bit);
+
+ return val;
+}
+
+static void gpio_set(struct w83627hf_sio_data *sio,
+ unsigned int bit, unsigned int status)
+{
+ u8 val;
+
+ val = superio_inb(sio, 0xf1);
+ if (status)
+ val |= (1 << bit);
+ else
+ val &= ~(1 << bit);
+ superio_outb(sio, 0xf1, val);
+}
+
+static void gpio1_enable(struct w83627hf_sio_data *sio)
+{
+ u8 val;
+
+ superio_enter(sio);
+
+ /* Select GPIO1 into pins multiplxer */
+ val = superio_inb(sio, W83627HF_LD_GPIO1_MUX);
+ superio_outb(sio, W83627HF_LD_GPIO1_MUX, val | 0xfc);
+
+ /* Enable GPIO1 */
+ superio_select(sio, W83627HF_LD_GPIO1);
+ val = superio_inb(sio, 0x30);
+ superio_outb(sio, 0x30, val | 0x01);
+
+ superio_exit(sio);
+}
+
+static void gpio1_disable(struct w83627hf_sio_data *sio)
+{
+ u8 val;
+
+ superio_enter(sio);
+
+ /* Disable GPIO1 */
+ superio_select(sio, W83627HF_LD_GPIO1);
+ val = superio_inb(sio, 0x30);
+ superio_outb(sio, 0x30, val & ~0x01);
+
+ superio_exit(sio);
+}
+
+static void gpio2_enable(struct w83627hf_sio_data *sio)
+{
+ u8 val;
+
+ superio_enter(sio);
+
+ /* Select GPIO2 into pins multiplxer */
+ val = superio_inb(sio, W83627HF_LD_GPIO1_MUX);
+ superio_outb(sio, W83627HF_LD_GPIO1_MUX, val | 0x01);
+ val = superio_inb(sio, W83627HF_LD_GPIO2_MUX);
+ superio_outb(sio, W83627HF_LD_GPIO2_MUX, val | 0xff);
+
+ /* Enable GPIO2 */
+ superio_select(sio, W83627HF_LD_GPIO2);
+ val = superio_inb(sio, 0x30);
+ superio_outb(sio, 0x30, val | 0x01);
+
+ superio_exit(sio);
+}
+
+static void gpio2_disable(struct w83627hf_sio_data *sio)
+{
+ u8 val;
+
+ superio_enter(sio);
+
+ /* Disable GPIO2 */
+ superio_select(sio, W83627HF_LD_GPIO2);
+ val = superio_inb(sio, 0x30);
+ superio_outb(sio, 0x30, val & ~0x01);
+
+ superio_exit(sio);
+}
+
+static void gpio3_enable(struct w83627hf_sio_data *sio)
+{
+ u8 val;
+
+ superio_enter(sio);
+
+ /* Select GPIO3 into pins multiplxer */
+ val = superio_inb(sio, W83627HF_LD_GPIO3_MUX);
+ superio_outb(sio, W83627HF_LD_GPIO3_MUX, val | 0xfc);
+
+ /* Enable GPIO3 */
+ superio_select(sio, W83627HF_LD_GPIO3);
+ val = superio_inb(sio, 0x30);
+ superio_outb(sio, 0x30, val | 0x01);
+
+ superio_exit(sio);
+}
+
+static void gpio3_disable(struct w83627hf_sio_data *sio)
+{
+ u8 val;
+
+ superio_enter(sio);
+
+ /* Disable GPIO3 */
+ superio_select(sio, W83627HF_LD_GPIO3);
+ val = superio_inb(sio, 0x30);
+ superio_outb(sio, 0x30, val & ~0x01);
+
+ superio_exit(sio);
+}
+
+/*
+ * GPIOs methods
+ */
+
+static int w83627hf_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct device *dev = chip->dev;
+ struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
+ struct w83627hf_data *data = container_of(chip,
+ struct w83627hf_data, chip);
+ struct bitmap *bit = data->bit;
+
+ switch (offset) {
+ case 0 ... 7:
+ gpio1_enable(sio_data);
+ break;
+
+ case 8 ... 15:
+ /* Port2 is currently not supported */
+ gpio2_enable(sio_data);
+ break;
+
+ case 16 ... 21:
+ gpio3_enable(sio_data);
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+ bit[offset].status = 1;
+
+ return 0;
+}
+
+static void w83627hf_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct device *dev = chip->dev;
+ struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
+ struct w83627hf_data *data = container_of(chip,
+ struct w83627hf_data, chip);
+ struct bitmap *bit = data->bit;
+ int i;
+
+ switch (offset) {
+ case 0 ... 7:
+ bit[offset].status = 0;
+ for (i = 0; i < 8; i++)
+ if (bit[i].status)
+ break;
+ if (i == 8)
+ gpio1_disable(sio_data);
+ break;
+
+ case 8 ... 15:
+ bit[offset].status = 0;
+ for (i = 8; i < 16; i++)
+ if (bit[i].status)
+ break;
+ if (i == 16)
+ gpio2_disable(sio_data);
+ break;
+
+ case 16 ... 21:
+ bit[offset].status = 0;
+ for (i = 16; i < 22; i++)
+ if (bit[i].status)
+ break;
+ if (i == 22)
+ gpio3_disable(sio_data);
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+static int w83627hf_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct device *dev = chip->dev;
+ struct w83627hf_sio_data *sio = dev->parent->platform_data;
+
+ superio_enter(sio);
+
+ switch (offset) {
+ case 0 ... 7:
+ superio_select(sio, W83627HF_LD_GPIO1);
+ gpio_mode(sio, offset, 1);
+ break;
+
+ case 8 ... 15:
+ superio_select(sio, W83627HF_LD_GPIO2);
+ gpio_mode(sio, offset - 8, 1);
+ break;
+
+ case 16 ... 21:
+ superio_select(sio, W83627HF_LD_GPIO3);
+ gpio_mode(sio, offset - 16, 1);
+ break;
+
+ default:
+ BUG();
+ }
+
+ superio_exit(sio);
+
+ return 0;
+}
+
+static int w83627hf_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct device *dev = chip->dev;
+ struct w83627hf_sio_data *sio = dev->parent->platform_data;
+ u8 val;
+
+ superio_enter(sio);
+
+ switch (offset) {
+ case 0 ... 7:
+ superio_select(sio, W83627HF_LD_GPIO1);
+ val = gpio_get(sio, offset);
+ break;
+
+ case 8 ... 15:
+ superio_select(sio, W83627HF_LD_GPIO2);
+ val = gpio_get(sio, offset - 8);
+ break;
+
+ case 16 ... 21:
+ superio_select(sio, W83627HF_LD_GPIO3);
+ val = gpio_get(sio, offset - 16);
+ break;
+
+ default:
+ BUG();
+ val = -EINVAL;
+ }
+
+ superio_exit(sio);
+
+ return val;
+}
+
+static int w83627hf_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct device *dev = chip->dev;
+ struct w83627hf_sio_data *sio = dev->parent->platform_data;
+ int ret = 0;
+
+ superio_enter(sio);
+
+ switch (offset) {
+ case 0 ... 7:
+ superio_select(sio, W83627HF_LD_GPIO1);
+ gpio_mode(sio, offset, 0);
+ break;
+
+ case 8 ... 15:
+ superio_select(sio, W83627HF_LD_GPIO2);
+ gpio_mode(sio, offset - 8, value);
+ break;
+
+ case 16 ... 21:
+ superio_select(sio, W83627HF_LD_GPIO3);
+ gpio_mode(sio, offset - 16, value);
+ break;
+
+ default:
+ BUG();
+ }
+
+ superio_exit(sio);
+
+ return ret;
+}
+
+static void w83627hf_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct device *dev = chip->dev;
+ struct w83627hf_sio_data *sio = dev->parent->platform_data;
+
+ superio_enter(sio);
+
+ switch (offset) {
+ case 0 ... 7:
+ superio_select(sio, W83627HF_LD_GPIO1);
+ gpio_set(sio, offset, value);
+ break;
+
+ case 8 ... 15:
+ superio_select(sio, W83627HF_LD_GPIO2);
+ gpio_set(sio, offset - 8, value);
+ break;
+
+ case 16 ... 21:
+ superio_select(sio, W83627HF_LD_GPIO3);
+ gpio_set(sio, offset - 16, value);
+ break;
+
+ default:
+ BUG();
+ }
+
+ superio_exit(sio);
+}
+
+static int __devinit w83627hf_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
+ struct w83627hf_data *data;
+ int err;
+
+ if (ngpio[sio_data->type] == 0) {
+ dev_err(&pdev->dev, "gpio support not available "
+ "for this chip type\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, data);
+
+ data->chip.base = -1;
+ data->chip.ngpio = ngpio[sio_data->type];
+ data->chip.label = sio_data->name;
+ data->chip.dev = dev;
+
+ data->chip.owner = THIS_MODULE;
+ data->chip.request = w83627hf_request;
+ data->chip.free = w83627hf_free;
+ data->chip.direction_input = w83627hf_direction_in;
+ data->chip.get = w83627hf_get;
+ data->chip.direction_output = w83627hf_direction_out;
+ data->chip.set = w83627hf_set;
+ data->chip.can_sleep = 1;
+
+ err = gpiochip_add(&data->chip);
+ if (err < 0) {
+ dev_err(&pdev->dev, "could not register gpiochip, %d\n", err);
+ goto free_platform_data;
+ }
+
+ return 0;
+
+free_platform_data:
+ kfree(data);
+ platform_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+static int __devexit w83627hf_remove(struct platform_device *pdev)
+{
+ struct w83627hf_data *data = platform_get_drvdata(pdev);
+ int err;
+
+ err = gpiochip_remove(&data->chip);
+ if (err < 0) {
+ dev_err(&pdev->dev, "could not deregister gpiochip, %d\n", err);
+ return err;
+ }
+
+ kfree(data);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver w83627hf_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME "_gpio",
+ },
+ .probe = w83627hf_probe,
+ .remove = __devexit_p(w83627hf_remove),
+};
+
+/*
+ * Module stuff
+ */
+
+static int __init gpio_w83627hf_init(void)
+{
+ return platform_driver_register(&w83627hf_driver);
+}
+
+static void __exit gpio_w83627hf_exit(void)
+{
+ platform_driver_unregister(&w83627hf_driver);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@xxxxxxxxxxx>");
+MODULE_DESCRIPTION("W83627HF gpio driver");
+MODULE_LICENSE("GPL");
+
+module_init(gpio_w83627hf_init);
+module_exit(gpio_w83627hf_exit);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index cb351d3..029b8b1 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1272,6 +1272,7 @@ config SENSORS_W83L786NG
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
depends on !PPC
+ select MFD_W83627HF
select HWMON_VID
help
If you say yes here you get support for the Winbond W836X7 series
--
1.7.4.1


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