lkml.org 
[lkml]   [2012]   [Jan]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patches in this message
    /
    Date
    From
    SubjectRe: [RFC][PATCH 2/2] hwmon: (w83627ehf) Add GPIO port 3 functionality
    Hi Rodolfo,

    On 15-Jan-12 4:53 AM, Rodolfo Giometti wrote:
    > On Sat, Jan 14, 2012 at 04:15:08PM -0600, Alejandro wrote:
    >>
    >> The patch looks great, and it is definitely more maintainable. I'll
    >> create a patch for the w83627ehf driver and send it as soon as
    >> possible. Should I make the patch for the w83627hf or wait for
    >> Rodolfo???
    >
    > I already sent a new version of my patches... here you can find a copy
    > of my message:
    >
    > http://www.spinics.net/lists/lm-sensors/msg33656.html
    >
    > Please, ask to me whatever you need since I'd like very much these
    > patches will be added to the kernel main tree! :)
    >
    > Ciao,
    >
    > Rodolfo

    The patch as it is posted on "lm-sensors/msg33656.html" mailing list
    does not apply to the latest tree. After making some changes it applies
    cleanly to 3.2 tree. The issues were:

    -The gpio naming convention is now "gpio-[name of the driver]" instead
    of "[name of driver]_gpio"
    -Line changes in the Kconfig
    -Some email addresses converted to @xxxxxxx (by the lm-sensors mailing
    list I guess)

    Please look at the attachments for the new patches (I take no credit for
    the changes as it was a trivial clean-up), if you like the changes I
    would recommend starting a new thread on this list to get reviews.

    Note: I couldn't test the driver because my platform has not an HF chip
    but the patch looks good so far =)

    BR!

    Alex
    From 932beeb80d022c5bab861ea4d8d78cd82cae0bba Mon Sep 17 00:00:00 2001
    From: Alejandro del Rio <scasbyte@gmail.com>
    Date: Mon, 16 Jan 2012 00:32:21 -0800
    Subject: [PATCH 1/2] [temporal change]

    [temporal change]


    Signed-off-by: Alejandro del Rio <scasbyte@gmail.com>
    ---
    drivers/hwmon/w83627hf.c | 331 ++++++++++++----------------------------------
    1 files changed, 86 insertions(+), 245 deletions(-)

    diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
    index 374118f..3c29146 100644
    --- a/drivers/hwmon/w83627hf.c
    +++ b/drivers/hwmon/w83627hf.c
    @@ -6,6 +6,8 @@
    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>
    + MFD support added by Rodolfo Giometti <giometti@enneenne.it>
    + Copyright (c) 2010 Rodolfo Giometti <giometti@enneenne.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
    @@ -54,17 +56,10 @@
    #include <linux/ioport.h>
    #include <linux/acpi.h>
    #include <linux/io.h>
    +#include <linux/mfd/w83627hf.h>
    #include "lm75.h"

    -static struct platform_device *pdev;

    -#define DRVNAME "w83627hf"
    -enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
    -
    -struct w83627hf_sio_data {
    - enum chips type;
    - int sioaddr;
    -};

    static u8 force_i2c = 0x1f;
    module_param(force_i2c, byte, 0);
    @@ -75,86 +70,8 @@ static bool init = 1;
    module_param(init, bool, 0);
    MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");

    -static unsigned short force_id;
    -module_param(force_id, ushort, 0);
    -MODULE_PARM_DESC(force_id, "Override the detected device ID");
    -
    -/* modified from kernel/include/traps.c */
    -#define DEV 0x07 /* Register: Logical device select */
    -
    -/* logical device numbers for superio_select (below) */
    -#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_GPIO3 0x09
    -#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */
    -#define W83627HF_LD_ACPI 0x0a
    -#define W83627HF_LD_HWM 0x0b
    -
    -#define DEVID 0x20 /* Register: Device ID */
    -
    -#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */
    -#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 */
    -
    -static inline void
    -superio_outb(struct w83627hf_sio_data *sio, int reg, int val)
    -{
    - outb(reg, sio->sioaddr);
    - outb(val, sio->sioaddr + 1);
    -}
    -
    -static inline int
    -superio_inb(struct w83627hf_sio_data *sio, int reg)
    -{
    - outb(reg, sio->sioaddr);
    - return inb(sio->sioaddr + 1);
    -}
    -
    -static inline void
    -superio_select(struct w83627hf_sio_data *sio, int ld)
    -{
    - outb(DEV, sio->sioaddr);
    - outb(ld, sio->sioaddr + 1);
    -}
    -
    -static inline void
    -superio_enter(struct w83627hf_sio_data *sio)
    -{
    - outb(0x87, sio->sioaddr);
    - outb(0x87, sio->sioaddr);
    -}
    -
    -static inline void
    -superio_exit(struct w83627hf_sio_data *sio)
    -{
    - outb(0xAA, sio->sioaddr);
    -}
    -
    -#define W627_DEVID 0x52
    -#define W627THF_DEVID 0x82
    -#define W697_DEVID 0x60
    -#define W637_DEVID 0x70
    -#define W687THF_DEVID 0x85
    -#define WINB_ACT_REG 0x30
    -#define WINB_BASE_REG 0x60
    /* Constants specified below */

    -/* Alignment of the base address */
    -#define WINB_ALIGNMENT ~7
    -
    /* Offset & size of I/O region we are interested in */
    #define WINB_REGION_OFFSET 5
    #define WINB_REGION_SIZE 2
    @@ -394,7 +311,7 @@ static void w83627hf_init_device(struct platform_device *pdev);
    static struct platform_driver w83627hf_driver = {
    .driver = {
    .owner = THIS_MODULE,
    - .name = DRVNAME,
    + .name = DRVNAME "_hwmon",
    },
    .probe = w83627hf_probe,
    .remove = __devexit_p(w83627hf_remove),
    @@ -1123,70 +1040,6 @@ show_name(struct device *dev, struct device_attribute *devattr, char *buf)
    }
    static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);

    -static int __init w83627hf_find(int sioaddr, unsigned short *addr,
    - struct w83627hf_sio_data *sio_data)
    -{
    - int err = -ENODEV;
    - u16 val;
    -
    - static const __initdata char *names[] = {
    - "W83627HF",
    - "W83627THF",
    - "W83697HF",
    - "W83637HF",
    - "W83687THF",
    - };
    -
    - sio_data->sioaddr = sioaddr;
    - superio_enter(sio_data);
    - val = force_id ? force_id : superio_inb(sio_data, DEVID);
    - switch (val) {
    - case W627_DEVID:
    - sio_data->type = w83627hf;
    - break;
    - case W627THF_DEVID:
    - sio_data->type = w83627thf;
    - break;
    - case W697_DEVID:
    - sio_data->type = w83697hf;
    - break;
    - case W637_DEVID:
    - sio_data->type = w83637hf;
    - break;
    - case W687THF_DEVID:
    - sio_data->type = w83687thf;
    - break;
    - case 0xff: /* No device at all */
    - goto exit;
    - default:
    - pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%02x)\n", val);
    - goto exit;
    - }
    -
    - superio_select(sio_data, W83627HF_LD_HWM);
    - val = (superio_inb(sio_data, WINB_BASE_REG) << 8) |
    - superio_inb(sio_data, WINB_BASE_REG + 1);
    - *addr = val & WINB_ALIGNMENT;
    - if (*addr == 0) {
    - pr_warn("Base address not set, skipping\n");
    - goto exit;
    - }
    -
    - val = superio_inb(sio_data, WINB_ACT_REG);
    - if (!(val & 0x01)) {
    - pr_warn("Enabling HWM logical device\n");
    - superio_outb(sio_data, WINB_ACT_REG, val | 0x01);
    - }
    -
    - err = 0;
    - pr_info(DRVNAME ": Found %s chip at %#x\n",
    - names[sio_data->type], *addr);
    -
    - exit:
    - superio_exit(sio_data);
    - return err;
    -}
    -
    #define VIN_UNIT_ATTRS(_X_) \
    &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
    &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
    @@ -1265,27 +1118,81 @@ static const struct attribute_group w83627hf_group_opt = {
    .attrs = w83627hf_attributes_opt,
    };

    +static int w83627hf_enable_hwmon(struct w83627hf_sio_data *sio_data)
    +{
    + u16 val;
    + int ret;
    +
    + superio_enter(sio_data);
    +
    + superio_select(sio_data, W83627HF_LD_HWM);
    +
    + val = (superio_inb(sio_data, 0x60) << 8) |
    + superio_inb(sio_data, 0x60 + 1);
    + ret = val & (~7);
    + pr_info(DRVNAME ": hwmon chip %s at %#x\n", sio_data->name, ret);
    +
    + if (ret == 0) {
    + printk(KERN_WARNING DRVNAME ": Base address not set, "
    + "skipping\n");
    + ret = -EINVAL;
    + goto exit;
    + }
    +
    + val = superio_inb(sio_data, 0x30);
    + superio_outb(sio_data, 0x30, val | 0x01);
    +
    +exit:
    + superio_exit(sio_data);
    +
    + return ret;
    +}
    +
    +static void w83627hf_disable_hwmon(struct w83627hf_sio_data *sio_data)
    +{
    + u16 val;
    +
    + superio_enter(sio_data);
    +
    + superio_select(sio_data, W83627HF_LD_HWM);
    +
    + val = superio_inb(sio_data, 0x30);
    + superio_outb(sio_data, 0x30, val & ~0x01);
    +
    + superio_exit(sio_data);
    +}
    +
    static int __devinit w83627hf_probe(struct platform_device *pdev)
    {
    struct device *dev = &pdev->dev;
    - struct w83627hf_sio_data *sio_data = dev->platform_data;
    + struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
    struct w83627hf_data *data;
    - struct resource *res;
    int err, i;

    - static const char *names[] = {
    - "w83627hf",
    - "w83627thf",
    - "w83697hf",
    - "w83637hf",
    - "w83687thf",
    + struct resource res = {
    + .start = /* address + */ WINB_REGION_OFFSET,
    + .end = /* address + */ WINB_REGION_OFFSET +
    + WINB_REGION_SIZE - 1,
    + .name = DRVNAME "_hwmon",
    + .flags = IORESOURCE_IO,
    };

    - res = platform_get_resource(pdev, IORESOURCE_IO, 0);
    - if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
    + err = w83627hf_enable_hwmon(sio_data);
    + if (err < 0)
    + return err;
    +
    + /* Before doing our job we should fixup ioport range */
    + res.start += err;
    + res.end += err;
    +
    + err = acpi_check_resource_conflict(&res);
    + if (err)
    + goto ERROR0;
    +
    + if (!request_region(res.start, WINB_REGION_SIZE, DRVNAME "_hwmon")) {
    dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
    - (unsigned long)res->start,
    - (unsigned long)(res->start + WINB_REGION_SIZE - 1));
    + (unsigned long) res.start,
    + (unsigned long) (res.start + WINB_REGION_SIZE - 1));
    err = -EBUSY;
    goto ERROR0;
    }
    @@ -1294,9 +1201,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
    err = -ENOMEM;
    goto ERROR1;
    }
    - data->addr = res->start;
    + data->addr = res.start;
    data->type = sio_data->type;
    - data->name = names[sio_data->type];
    + data->name = sio_data->name;
    mutex_init(&data->lock);
    mutex_init(&data->update_lock);
    platform_set_drvdata(pdev, data);
    @@ -1429,15 +1336,20 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
    platform_set_drvdata(pdev, NULL);
    kfree(data);
    ERROR1:
    - release_region(res->start, WINB_REGION_SIZE);
    + release_region(res.start, WINB_REGION_SIZE);
    ERROR0:
    + w83627hf_disable_hwmon(sio_data);
    return err;
    }

    static int __devexit w83627hf_remove(struct platform_device *pdev)
    {
    + struct device *dev = &pdev->dev;
    + struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
    struct w83627hf_data *data = platform_get_drvdata(pdev);
    - struct resource *res;
    + unsigned int addr = data->addr;
    +
    + w83627hf_disable_hwmon(sio_data);

    hwmon_device_unregister(data->hwmon_dev);

    @@ -1446,8 +1358,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
    platform_set_drvdata(pdev, NULL);
    kfree(data);

    - res = platform_get_resource(pdev, IORESOURCE_IO, 0);
    - release_region(res->start, WINB_REGION_SIZE);
    + release_region(addr, WINB_REGION_SIZE);

    return 0;
    }
    @@ -1498,7 +1409,8 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)

    static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
    {
    - struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
    + struct device *dev = &pdev->dev;
    + struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
    int res = 0xff, sel;

    superio_enter(sio_data);
    @@ -1529,7 +1441,8 @@ exit:

    static int __devinit w83687thf_read_vid(struct platform_device *pdev)
    {
    - struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
    + struct device *dev = &pdev->dev;
    + struct w83627hf_sio_data *sio_data = dev->parent->platform_data;
    int res = 0xff;

    superio_enter(sio_data);
    @@ -1772,92 +1685,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
    return data;
    }

    -static int __init w83627hf_device_add(unsigned short address,
    - const struct w83627hf_sio_data *sio_data)
    -{
    - struct resource res = {
    - .start = address + WINB_REGION_OFFSET,
    - .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
    - .name = DRVNAME,
    - .flags = IORESOURCE_IO,
    - };
    - int err;
    -
    - err = acpi_check_resource_conflict(&res);
    - if (err)
    - goto exit;
    -
    - pdev = platform_device_alloc(DRVNAME, address);
    - if (!pdev) {
    - err = -ENOMEM;
    - pr_err("Device allocation failed\n");
    - goto exit;
    - }
    -
    - err = platform_device_add_resources(pdev, &res, 1);
    - if (err) {
    - pr_err("Device resource addition failed (%d)\n", err);
    - goto exit_device_put;
    - }
    -
    - err = platform_device_add_data(pdev, sio_data,
    - sizeof(struct w83627hf_sio_data));
    - if (err) {
    - pr_err("Platform data allocation failed\n");
    - goto exit_device_put;
    - }
    -
    - err = platform_device_add(pdev);
    - if (err) {
    - pr_err("Device addition failed (%d)\n", err);
    - goto exit_device_put;
    - }
    -
    - return 0;
    -
    -exit_device_put:
    - platform_device_put(pdev);
    -exit:
    - return err;
    -}
    -
    static int __init sensors_w83627hf_init(void)
    {
    - int err;
    - unsigned short address;
    - struct w83627hf_sio_data sio_data;
    -
    - if (w83627hf_find(0x2e, &address, &sio_data)
    - && w83627hf_find(0x4e, &address, &sio_data))
    - return -ENODEV;
    -
    - err = platform_driver_register(&w83627hf_driver);
    - if (err)
    - goto exit;
    -
    - /* Sets global pdev as a side effect */
    - err = w83627hf_device_add(address, &sio_data);
    - if (err)
    - goto exit_driver;
    -
    - return 0;
    -
    -exit_driver:
    - platform_driver_unregister(&w83627hf_driver);
    -exit:
    - return err;
    + return platform_driver_register(&w83627hf_driver);
    }

    static void __exit sensors_w83627hf_exit(void)
    {
    - platform_device_unregister(pdev);
    platform_driver_unregister(&w83627hf_driver);
    }

    MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
    "Philip Edelbrock <phil@netroedge.com>, "
    "and Mark Studebaker <mdsxyz123@yahoo.com>");
    -MODULE_DESCRIPTION("W83627HF driver");
    +MODULE_DESCRIPTION("W83627HF hwmon driver");
    MODULE_LICENSE("GPL");

    module_init(sensors_w83627hf_init);
    --
    1.7.4.1
    From 0aed2aee358992d46ebfc2783569a8b3c350bd63 Mon Sep 17 00:00:00 2001
    From: Alejandro del Rio <scasbyte@gmail.com>
    Date: Mon, 16 Jan 2012 00:33:05 -0800
    Subject: [PATCH 2/2] [temporal change]

    [temporal change]


    Signed-off-by: Alejandro del Rio <scasbyte@gmail.com>
    ---
    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@enneenne.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/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@enneenne.it>");
    +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
    \
     
     \ /
      Last update: 2012-01-16 10:45    [W:0.079 / U:0.640 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site