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