18950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du/* Moorestown PMIC GPIO (access through IPC) driver
28950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * Copyright (c) 2008 - 2009, Intel Corporation.
38950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du *
48950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * This program is free software; you can redistribute it and/or modify
58950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * it under the terms of the GNU General Public License version 2 as
68950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * published by the Free Software Foundation.
78950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du *
88950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * This program is distributed in the hope that it will be useful,
98950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * but WITHOUT ANY WARRANTY; without even the implied warranty of
108950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
118950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * GNU General Public License for more details.
128950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du *
138950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * You should have received a copy of the GNU General Public License
148950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * along with this program; if not, write to the Free Software
158950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
168950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du */
178950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
188950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du/* Supports:
198950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * Moorestown platform PMIC chip
208950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du */
218950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
229a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches#define pr_fmt(fmt) "%s: " fmt, __func__
239a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches
248950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/module.h>
258950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/kernel.h>
268950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/interrupt.h>
278950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/delay.h>
288950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/stddef.h>
298950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/slab.h>
308950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/ioport.h>
318950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/init.h>
328950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/io.h>
338950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/gpio.h>
348950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <asm/intel_scu_ipc.h>
358950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/device.h>
368950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/intel_pmic_gpio.h>
378950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#include <linux/platform_device.h>
388950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
398950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define DRIVER_NAME "pmic_gpio"
408950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
418950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du/* register offset that IPC driver should use
428950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * 8 GPIO + 8 GPOSW (6 controllable) + 8GPO
438950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du */
448950778704cf8483cc5cc0140f557adf0d3f45a5Alek Duenum pmic_gpio_register {
458950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	GPIO0		= 0xE0,
468950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	GPIO7		= 0xE7,
478950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	GPIOINT		= 0xE8,
488950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	GPOSWCTL0	= 0xEC,
498950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	GPOSWCTL5	= 0xF1,
508950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	GPO		= 0xF4,
518950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du};
528950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
538950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du/* bits definition for GPIO & GPOSW */
548950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPIO_DRV 0x01
558950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPIO_DIR 0x02
568950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPIO_DIN 0x04
578950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPIO_DOU 0x08
588950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPIO_INTCTL 0x30
598950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPIO_DBC 0xc0
608950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
618950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPOSW_DRV 0x01
628950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPOSW_DOU 0x08
638950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define GPOSW_RDRV 0x30
648950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
65d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner#define GPIO_UPDATE_TYPE	0x80000000
668950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
678950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du#define NUM_GPIO 24
688950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
698950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustruct pmic_gpio {
70d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner	struct mutex		buslock;
718950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	struct gpio_chip	chip;
728950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	void			*gpiointr;
738950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int			irq;
748950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	unsigned		irq_base;
75d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner	unsigned int		update_type;
76d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner	u32			trigger_type;
778950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du};
788950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
7965d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixnerstatic void pmic_program_irqtype(int gpio, int type)
8065d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner{
8165d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	if (type & IRQ_TYPE_EDGE_RISING)
8265d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20);
8365d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	else
8465d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20);
8565d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
8665d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	if (type & IRQ_TYPE_EDGE_FALLING)
8765d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10);
8865d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	else
8965d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10);
9065d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner};
9165d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
928950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
938950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
948950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (offset > 8) {
959a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches		pr_err("only pin 0-7 support input\n");
968950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return -1;/* we only have 8 GPIO can use as input */
978950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
988950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return intel_scu_ipc_update_register(GPIO0 + offset,
998950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du							GPIO_DIR, GPIO_DIR);
1008950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
1018950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1028950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic int pmic_gpio_direction_output(struct gpio_chip *chip,
1038950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du			unsigned offset, int value)
1048950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
1058950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int rc = 0;
1068950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1078950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (offset < 8)/* it is GPIO */
1088950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		rc = intel_scu_ipc_update_register(GPIO0 + offset,
109ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du				GPIO_DRV | (value ? GPIO_DOU : 0),
110ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du				GPIO_DRV | GPIO_DOU | GPIO_DIR);
1118950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	else if (offset < 16)/* it is GPOSW */
1128950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
113ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du				GPOSW_DRV | (value ? GPOSW_DOU : 0),
114ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du				GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
1158950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	else if (offset > 15 && offset < 24)/* it is GPO */
1168950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		rc = intel_scu_ipc_update_register(GPO,
117ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du				value ? 1 << (offset - 16) : 0,
118ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du				1 << (offset - 16));
1198950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	else {
1209a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches		pr_err("invalid PMIC GPIO pin %d!\n", offset);
1218950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		WARN_ON(1);
1228950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
1238950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1248950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return rc;
1258950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
1268950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1278950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic int pmic_gpio_get(struct gpio_chip *chip, unsigned offset)
1288950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
1298950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	u8 r;
1308950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int ret;
1318950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1328950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	/* we only have 8 GPIO pins we can use as input */
1338950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (offset > 8)
1348950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return -EOPNOTSUPP;
1358950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r);
1368950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (ret < 0)
1378950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return ret;
1388950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return r & GPIO_DIN;
1398950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
1408950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1418950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
1428950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
1438950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (offset < 8)/* it is GPIO */
1448950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		intel_scu_ipc_update_register(GPIO0 + offset,
145ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du			GPIO_DRV | (value ? GPIO_DOU : 0),
146ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du			GPIO_DRV | GPIO_DOU);
1478950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	else if (offset < 16)/* it is GPOSW */
1488950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8,
149ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du			GPOSW_DRV | (value ? GPOSW_DOU : 0),
150ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du			GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV);
1518950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	else if (offset > 15 && offset < 24) /* it is GPO */
1528950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		intel_scu_ipc_update_register(GPO,
153ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du			value ? 1 << (offset - 16) : 0,
154ffcfff3a8d6cc94f1fb598e0b021c64ce35b5036Alek Du			1 << (offset - 16));
1558950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
1568950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
157d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner/*
158d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner * This is called from genirq with pg->buslock locked and
159d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner * irq_desc->lock held. We can not access the scu bus here, so we
160d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner * store the change and update in the bus_sync_unlock() function below
161d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner */
162cb8e5e6a60cab5a90afd45d49655458c6e1db78cThomas Gleixnerstatic int pmic_irq_type(struct irq_data *data, unsigned type)
1638950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
164cb8e5e6a60cab5a90afd45d49655458c6e1db78cThomas Gleixner	struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
165cb8e5e6a60cab5a90afd45d49655458c6e1db78cThomas Gleixner	u32 gpio = data->irq - pg->irq_base;
1668950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1674119617919c243755946699808ffd0f4befa62c7Axel Lin	if (gpio >= pg->chip.ngpio)
1688950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return -EINVAL;
1698950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
170d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner	pg->trigger_type = type;
171d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner	pg->update_type = gpio | GPIO_UPDATE_TYPE;
1728950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return 0;
1738950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
1748950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1758950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
1768950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
1778950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip);
1788950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
1798950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return pg->irq_base + offset;
1808950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
1818950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
18265d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixnerstatic void pmic_bus_lock(struct irq_data *data)
18365d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner{
18465d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
18565d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
18665d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	mutex_lock(&pg->buslock);
18765d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner}
18865d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
18965d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixnerstatic void pmic_bus_sync_unlock(struct irq_data *data)
19065d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner{
19165d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	struct pmic_gpio *pg = irq_data_get_irq_chip_data(data);
19265d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
19365d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	if (pg->update_type) {
19465d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE;
19565d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
19665d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		pmic_program_irqtype(gpio, pg->trigger_type);
19765d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner		pg->update_type = 0;
19865d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	}
19965d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	mutex_unlock(&pg->buslock);
20065d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner}
20165d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner
2028950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du/* the gpiointr register is read-clear, so just do nothing. */
203cb8e5e6a60cab5a90afd45d49655458c6e1db78cThomas Gleixnerstatic void pmic_irq_unmask(struct irq_data *data) { }
2048950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
205cb8e5e6a60cab5a90afd45d49655458c6e1db78cThomas Gleixnerstatic void pmic_irq_mask(struct irq_data *data) { }
2068950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2078950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic struct irq_chip pmic_irqchip = {
20865d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	.name			= "PMIC-GPIO",
20965d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	.irq_mask		= pmic_irq_mask,
21065d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	.irq_unmask		= pmic_irq_unmask,
21165d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	.irq_set_type		= pmic_irq_type,
21221a8d026e0721f90ae03084e96a215632c80fc13Matthew Garrett	.irq_bus_lock		= pmic_bus_lock,
21365d7ac038e34702feedad91d0bf597b1f0a4174aThomas Gleixner	.irq_bus_sync_unlock	= pmic_bus_sync_unlock,
2148950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du};
2158950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
21698401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixnerstatic irqreturn_t pmic_irq_handler(int irq, void *data)
2178950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
21898401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner	struct pmic_gpio *pg = data;
2198950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	u8 intsts = *((u8 *)pg->gpiointr + 4);
2208950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int gpio;
22198401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner	irqreturn_t ret = IRQ_NONE;
2228950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2238950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	for (gpio = 0; gpio < 8; gpio++) {
2248950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		if (intsts & (1 << gpio)) {
2258950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du			pr_debug("pmic pin %d triggered\n", gpio);
2268950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du			generic_handle_irq(pg->irq_base + gpio);
22798401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner			ret = IRQ_HANDLED;
2288950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		}
2298950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
23098401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner	return ret;
2318950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
2328950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2338950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
2348950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
2358950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	struct device *dev = &pdev->dev;
2368950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int irq = platform_get_irq(pdev, 0);
2378950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	struct intel_pmic_gpio_platform_data *pdata = dev->platform_data;
2388950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2398950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	struct pmic_gpio *pg;
2408950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int retval;
2418950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	int i;
2428950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2438950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (irq < 0) {
2448950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		dev_dbg(dev, "no IRQ line\n");
2458950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return -EINVAL;
2468950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
2478950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2488950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (!pdata || !pdata->gpio_base || !pdata->irq_base) {
2498950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		dev_dbg(dev, "incorrect or missing platform data\n");
2508950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return -EINVAL;
2518950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
2528950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2538950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg = kzalloc(sizeof(*pg), GFP_KERNEL);
2548950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (!pg)
2558950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		return -ENOMEM;
2568950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2578950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	dev_set_drvdata(dev, pg);
2588950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2598950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->irq = irq;
2608950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	/* setting up SRAM mapping for GPIOINT register */
2618950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->gpiointr = ioremap_nocache(pdata->gpiointr, 8);
2628950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (!pg->gpiointr) {
2639a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches		pr_err("Can not map GPIOINT\n");
2648950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		retval = -EINVAL;
2658950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		goto err2;
2668950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
2678950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->irq_base = pdata->irq_base;
2688950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.label = "intel_pmic";
2698950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.direction_input = pmic_gpio_direction_input;
2708950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.direction_output = pmic_gpio_direction_output;
2718950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.get = pmic_gpio_get;
2728950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.set = pmic_gpio_set;
2738950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.to_irq = pmic_gpio_to_irq;
2748950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.base = pdata->gpio_base;
2758950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.ngpio = NUM_GPIO;
2768950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.can_sleep = 1;
2778950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.dev = dev;
2788950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
279d4b7de612d193e1c8fdeee9902e5a582e746dfe9Thomas Gleixner	mutex_init(&pg->buslock);
2808950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
2818950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	pg->chip.dev = dev;
2828950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	retval = gpiochip_add(&pg->chip);
2838950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	if (retval) {
2849a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches		pr_err("Can not add pmic gpio chip\n");
2858950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		goto err;
2868950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
28798401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner
28898401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner	retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg);
28998401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner	if (retval) {
2909a2ffd168ef8ec3705060ffb21d6dcb20eeb9506Joe Perches		pr_warn("Interrupt request failed\n");
29198401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner		goto err;
29298401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner	}
29398401ae43413ac374c0eb8d6018b13495e08f948Thomas Gleixner
2948950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	for (i = 0; i < 8; i++) {
295dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner		irq_set_chip_and_handler_name(i + pg->irq_base,
296dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner					      &pmic_irqchip,
297dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner					      handle_simple_irq,
298dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner					      "demux");
299dced35aeb0367dda2636ee9ee914bda14510dcc9Thomas Gleixner		irq_set_chip_data(i + pg->irq_base, pg);
3008950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	}
3018950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return 0;
3028950778704cf8483cc5cc0140f557adf0d3f45a5Alek Duerr:
3038950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	iounmap(pg->gpiointr);
3048950778704cf8483cc5cc0140f557adf0d3f45a5Alek Duerr2:
3058950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	kfree(pg);
3068950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return retval;
3078950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
3088950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
3098950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du/* at the same time, register a platform driver
3108950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du * this supports the sfi 0.81 fw */
3118950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic struct platform_driver platform_pmic_gpio_driver = {
3128950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	.driver = {
3138950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		.name		= DRIVER_NAME,
3148950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du		.owner		= THIS_MODULE,
3158950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	},
3168950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	.probe		= platform_pmic_gpio_probe,
3178950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du};
3188950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
3198950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dustatic int __init platform_pmic_gpio_init(void)
3208950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du{
3218950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du	return platform_driver_register(&platform_pmic_gpio_driver);
3228950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du}
3238950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
3248950778704cf8483cc5cc0140f557adf0d3f45a5Alek Dusubsys_initcall(platform_pmic_gpio_init);
3258950778704cf8483cc5cc0140f557adf0d3f45a5Alek Du
3268950778704cf8483cc5cc0140f557adf0d3f45a5Alek DuMODULE_AUTHOR("Alek Du <alek.du@intel.com>");
3278950778704cf8483cc5cc0140f557adf0d3f45a5Alek DuMODULE_DESCRIPTION("Intel Moorestown PMIC GPIO driver");
3288950778704cf8483cc5cc0140f557adf0d3f45a5Alek DuMODULE_LICENSE("GPL v2");
329