19cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev/*
2c103de240439dfee24ac50eb99c8be3a30d13323Grant Likely *  GPIO interface for IT8761E Super I/O chip
39cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *
49cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  Author: Denis Turischev <denis@compulab.co.il>
59cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *
69cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  This program is free software; you can redistribute it and/or modify
79cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  it under the terms of the GNU General Public License 2 as published
89cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  by the Free Software Foundation.
99cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *
109cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  This program is distributed in the hope that it will be useful,
119cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  but WITHOUT ANY WARRANTY; without even the implied warranty of
129cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
139cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  GNU General Public License for more details.
149cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *
159cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  You should have received a copy of the GNU General Public License
169cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  along with this program; see the file COPYING.  If not, write to
179cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
189cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev */
199cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
209cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/init.h>
219cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/kernel.h>
229cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/module.h>
239cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/io.h>
249cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/errno.h>
259cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/ioport.h>
269cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
279cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#include <linux/gpio.h>
289cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
299cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define SIO_CHIP_ID		0x8761
309cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define CHIP_ID_HIGH_BYTE	0x20
319cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define CHIP_ID_LOW_BYTE	0x21
329cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
339cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic u8 ports[2] = { 0x2e, 0x4e };
349cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic u8 port;
359cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
369cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic DEFINE_SPINLOCK(sio_lock);
379cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
389cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define GPIO_NAME		"it8761-gpio"
399cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define GPIO_BA_HIGH_BYTE	0x60
409cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define GPIO_BA_LOW_BYTE	0x61
419cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define GPIO_IOSIZE		4
429cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define GPIO1X_IO		0xf0
439cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev#define GPIO2X_IO		0xf1
449cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
459cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic u16 gpio_ba;
469cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
479cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic u8 read_reg(u8 addr, u8 port)
489cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
499cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(addr, port);
509cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	return inb(port + 1);
519cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
529cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
539cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic void write_reg(u8 data, u8 addr, u8 port)
549cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
559cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(addr, port);
569cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(data, port + 1);
579cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
589cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
599cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic void enter_conf_mode(u8 port)
609cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
619cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(0x87, port);
629cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(0x61, port);
639cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(0x55, port);
649cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb((port == 0x2e) ? 0x55 : 0xaa, port);
659cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
669cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
679cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic void exit_conf_mode(u8 port)
689cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
699cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(0x2, port);
709cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	outb(0x2, port + 1);
719cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
729cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
739cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic void enter_gpio_mode(u8 port)
749cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
759cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	write_reg(0x2, 0x7, port);
769cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
779cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
789cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic int it8761e_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
799cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
809cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u16 reg;
819cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u8 bit;
829cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
833c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	bit = gpio_num % 8;
843c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
859cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
869cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	return !!(inb(reg) & (1 << bit));
879cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
889cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
899cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic int it8761e_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
909cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
919cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u8 curr_dirs;
929cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u8 io_reg, bit;
939cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
943c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	bit = gpio_num % 8;
953c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
969cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
979cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	spin_lock(&sio_lock);
989cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
999cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	enter_conf_mode(port);
1009cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	enter_gpio_mode(port);
1019cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1029cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	curr_dirs = read_reg(io_reg, port);
1039cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1049cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (curr_dirs & (1 << bit))
1059cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		write_reg(curr_dirs & ~(1 << bit), io_reg, port);
1069cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1079cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	exit_conf_mode(port);
1089cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1099cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	spin_unlock(&sio_lock);
1109cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	return 0;
1119cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
1129cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1139cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic void it8761e_gpio_set(struct gpio_chip *gc,
1149cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev				unsigned gpio_num, int val)
1159cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
1169cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u8 curr_vals, bit;
1179cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u16 reg;
1189cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1193c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	bit = gpio_num % 8;
1203c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
1219cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1229cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	spin_lock(&sio_lock);
1239cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1249cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	curr_vals = inb(reg);
1259cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (val)
1269cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		outb(curr_vals | (1 << bit) , reg);
1279cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	else
1289cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		outb(curr_vals & ~(1 << bit), reg);
1299cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1309cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	spin_unlock(&sio_lock);
1319cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
1329cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1339cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic int it8761e_gpio_direction_out(struct gpio_chip *gc,
1349cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev					unsigned gpio_num, int val)
1359cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
1369cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	u8 curr_dirs, io_reg, bit;
1379cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1383c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	bit = gpio_num % 8;
1393c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
1409cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1419cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	it8761e_gpio_set(gc, gpio_num, val);
1429cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1439cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	spin_lock(&sio_lock);
1449cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1459cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	enter_conf_mode(port);
1469cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	enter_gpio_mode(port);
1479cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1489cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	curr_dirs = read_reg(io_reg, port);
1499cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1509cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (!(curr_dirs & (1 << bit)))
1519cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		write_reg(curr_dirs | (1 << bit), io_reg, port);
1529cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1539cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	exit_conf_mode(port);
1549cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1559cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	spin_unlock(&sio_lock);
1569cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	return 0;
1579cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
1589cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1599cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic struct gpio_chip it8761e_gpio_chip = {
1609cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	.label			= GPIO_NAME,
1619cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	.owner			= THIS_MODULE,
1629cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	.get			= it8761e_gpio_get,
1639cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	.direction_input	= it8761e_gpio_direction_in,
1649cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	.set			= it8761e_gpio_set,
1659cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	.direction_output	= it8761e_gpio_direction_out,
1669cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev};
1679cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1689cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic int __init it8761e_gpio_init(void)
1699cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
1709cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	int i, id, err;
1719cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1729cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	/* chip and port detection */
1739cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	for (i = 0; i < ARRAY_SIZE(ports); i++) {
1749cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		spin_lock(&sio_lock);
1759cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		enter_conf_mode(ports[i]);
1769cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1779cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		id = (read_reg(CHIP_ID_HIGH_BYTE, ports[i]) << 8) +
1789cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev				read_reg(CHIP_ID_LOW_BYTE, ports[i]);
1799cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1809cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		exit_conf_mode(ports[i]);
1819cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		spin_unlock(&sio_lock);
1829cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1839cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		if (id == SIO_CHIP_ID) {
1849cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev			port = ports[i];
1859cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev			break;
1869cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		}
1879cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	}
1889cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1899cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (!port)
1909cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		return -ENODEV;
1919cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1929cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	/* fetch GPIO base address */
1939cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	enter_conf_mode(port);
1949cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	enter_gpio_mode(port);
1959cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	gpio_ba = (read_reg(GPIO_BA_HIGH_BYTE, port) << 8) +
1969cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev				read_reg(GPIO_BA_LOW_BYTE, port);
1979cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	exit_conf_mode(port);
1989cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
1999cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (!request_region(gpio_ba, GPIO_IOSIZE, GPIO_NAME))
2009cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		return -EBUSY;
2019cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2029cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	it8761e_gpio_chip.base = -1;
2033c904afd7358e9ef515eb5df36b6f25c2b7fc2daDenis Turischev	it8761e_gpio_chip.ngpio = 16;
2049cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2059cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	err = gpiochip_add(&it8761e_gpio_chip);
2069cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (err < 0)
2079cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		goto gpiochip_add_err;
2089cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2099cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	return 0;
2109cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2119cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevgpiochip_add_err:
2129cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	release_region(gpio_ba, GPIO_IOSIZE);
2139cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	gpio_ba = 0;
2149cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	return err;
2159cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
2169cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2179cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevstatic void __exit it8761e_gpio_exit(void)
2189cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev{
2199cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	if (gpio_ba) {
22048baa18b250d5e36ed9f9bb04cdf812d74da08caDaniel Mack		int ret = gpiochip_remove(&it8761e_gpio_chip);
22148baa18b250d5e36ed9f9bb04cdf812d74da08caDaniel Mack
22248baa18b250d5e36ed9f9bb04cdf812d74da08caDaniel Mack		WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n",
22348baa18b250d5e36ed9f9bb04cdf812d74da08caDaniel Mack				__func__, ret);
2249cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2259cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		release_region(gpio_ba, GPIO_IOSIZE);
2269cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev		gpio_ba = 0;
2279cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev	}
2289cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev}
2299cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevmodule_init(it8761e_gpio_init);
2309cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischevmodule_exit(it8761e_gpio_exit);
2319cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis Turischev
2329cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis TurischevMODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
2339cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis TurischevMODULE_DESCRIPTION("GPIO interface for IT8761E Super I/O chip");
2349cc0cb3c7d54f320b9eede6f4a49072ecadd864dDenis TurischevMODULE_LICENSE("GPL");
235