1/* 2 * GPIO interface for Intel Sodaville SoCs. 3 * 4 * Copyright (c) 2010, 2011 Intel Corporation 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License 2 as published 8 * by the Free Software Foundation. 9 * 10 */ 11 12#include <linux/errno.h> 13#include <linux/gpio.h> 14#include <linux/init.h> 15#include <linux/io.h> 16#include <linux/irq.h> 17#include <linux/interrupt.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/pci.h> 21#include <linux/platform_device.h> 22#include <linux/of_irq.h> 23#include <linux/basic_mmio_gpio.h> 24 25#define DRV_NAME "sdv_gpio" 26#define SDV_NUM_PUB_GPIOS 12 27#define PCI_DEVICE_ID_SDV_GPIO 0x2e67 28#define GPIO_BAR 0 29 30#define GPOUTR 0x00 31#define GPOER 0x04 32#define GPINR 0x08 33 34#define GPSTR 0x0c 35#define GPIT1R0 0x10 36#define GPIO_INT 0x14 37#define GPIT1R1 0x18 38 39#define GPMUXCTL 0x1c 40 41struct sdv_gpio_chip_data { 42 int irq_base; 43 void __iomem *gpio_pub_base; 44 struct irq_domain *id; 45 struct irq_chip_generic *gc; 46 struct bgpio_chip bgpio; 47}; 48 49static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type) 50{ 51 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 52 struct sdv_gpio_chip_data *sd = gc->private; 53 void __iomem *type_reg; 54 u32 reg; 55 56 if (d->hwirq < 8) 57 type_reg = sd->gpio_pub_base + GPIT1R0; 58 else 59 type_reg = sd->gpio_pub_base + GPIT1R1; 60 61 reg = readl(type_reg); 62 63 switch (type) { 64 case IRQ_TYPE_LEVEL_HIGH: 65 reg &= ~BIT(4 * (d->hwirq % 8)); 66 break; 67 68 case IRQ_TYPE_LEVEL_LOW: 69 reg |= BIT(4 * (d->hwirq % 8)); 70 break; 71 72 default: 73 return -EINVAL; 74 } 75 76 writel(reg, type_reg); 77 return 0; 78} 79 80static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data) 81{ 82 struct sdv_gpio_chip_data *sd = data; 83 u32 irq_stat = readl(sd->gpio_pub_base + GPSTR); 84 85 irq_stat &= readl(sd->gpio_pub_base + GPIO_INT); 86 if (!irq_stat) 87 return IRQ_NONE; 88 89 while (irq_stat) { 90 u32 irq_bit = __fls(irq_stat); 91 92 irq_stat &= ~BIT(irq_bit); 93 generic_handle_irq(irq_find_mapping(sd->id, irq_bit)); 94 } 95 96 return IRQ_HANDLED; 97} 98 99static int sdv_xlate(struct irq_domain *h, struct device_node *node, 100 const u32 *intspec, u32 intsize, irq_hw_number_t *out_hwirq, 101 u32 *out_type) 102{ 103 u32 line, type; 104 105 if (node != h->of_node) 106 return -EINVAL; 107 108 if (intsize < 2) 109 return -EINVAL; 110 111 line = *intspec; 112 *out_hwirq = line; 113 114 intspec++; 115 type = *intspec; 116 117 switch (type) { 118 case IRQ_TYPE_LEVEL_LOW: 119 case IRQ_TYPE_LEVEL_HIGH: 120 *out_type = type; 121 break; 122 default: 123 return -EINVAL; 124 } 125 return 0; 126} 127 128static struct irq_domain_ops irq_domain_sdv_ops = { 129 .xlate = sdv_xlate, 130}; 131 132static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, 133 struct pci_dev *pdev) 134{ 135 struct irq_chip_type *ct; 136 int ret; 137 138 sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1); 139 if (sd->irq_base < 0) 140 return sd->irq_base; 141 142 /* mask + ACK all interrupt sources */ 143 writel(0, sd->gpio_pub_base + GPIO_INT); 144 writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR); 145 146 ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED, 147 "sdv_gpio", sd); 148 if (ret) 149 goto out_free_desc; 150 151 /* 152 * This gpio irq controller latches level irqs. Testing shows that if 153 * we unmask & ACK the IRQ before the source of the interrupt is gone 154 * then the interrupt is active again. 155 */ 156 sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base, 157 sd->gpio_pub_base, handle_fasteoi_irq); 158 if (!sd->gc) { 159 ret = -ENOMEM; 160 goto out_free_irq; 161 } 162 163 sd->gc->private = sd; 164 ct = sd->gc->chip_types; 165 ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; 166 ct->regs.eoi = GPSTR; 167 ct->regs.mask = GPIO_INT; 168 ct->chip.irq_mask = irq_gc_mask_clr_bit; 169 ct->chip.irq_unmask = irq_gc_mask_set_bit; 170 ct->chip.irq_eoi = irq_gc_eoi; 171 ct->chip.irq_set_type = sdv_gpio_pub_set_type; 172 173 irq_setup_generic_chip(sd->gc, IRQ_MSK(SDV_NUM_PUB_GPIOS), 174 IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 175 IRQ_LEVEL | IRQ_NOPROBE); 176 177 sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS, 178 sd->irq_base, 0, &irq_domain_sdv_ops, sd); 179 if (!sd->id) { 180 ret = -ENODEV; 181 goto out_free_irq; 182 } 183 return 0; 184out_free_irq: 185 free_irq(pdev->irq, sd); 186out_free_desc: 187 irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); 188 return ret; 189} 190 191static int sdv_gpio_probe(struct pci_dev *pdev, 192 const struct pci_device_id *pci_id) 193{ 194 struct sdv_gpio_chip_data *sd; 195 unsigned long addr; 196 const void *prop; 197 int len; 198 int ret; 199 u32 mux_val; 200 201 sd = kzalloc(sizeof(struct sdv_gpio_chip_data), GFP_KERNEL); 202 if (!sd) 203 return -ENOMEM; 204 ret = pci_enable_device(pdev); 205 if (ret) { 206 dev_err(&pdev->dev, "can't enable device.\n"); 207 goto done; 208 } 209 210 ret = pci_request_region(pdev, GPIO_BAR, DRV_NAME); 211 if (ret) { 212 dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR); 213 goto disable_pci; 214 } 215 216 addr = pci_resource_start(pdev, GPIO_BAR); 217 if (!addr) { 218 ret = -ENODEV; 219 goto release_reg; 220 } 221 sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR)); 222 223 prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len); 224 if (prop && len == 4) { 225 mux_val = of_read_number(prop, 1); 226 writel(mux_val, sd->gpio_pub_base + GPMUXCTL); 227 } 228 229 ret = bgpio_init(&sd->bgpio, &pdev->dev, 4, 230 sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR, 231 NULL, sd->gpio_pub_base + GPOER, NULL, 0); 232 if (ret) 233 goto unmap; 234 sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS; 235 236 ret = gpiochip_add(&sd->bgpio.gc); 237 if (ret < 0) { 238 dev_err(&pdev->dev, "gpiochip_add() failed.\n"); 239 goto unmap; 240 } 241 242 ret = sdv_register_irqsupport(sd, pdev); 243 if (ret) 244 goto unmap; 245 246 pci_set_drvdata(pdev, sd); 247 dev_info(&pdev->dev, "Sodaville GPIO driver registered.\n"); 248 return 0; 249 250unmap: 251 iounmap(sd->gpio_pub_base); 252release_reg: 253 pci_release_region(pdev, GPIO_BAR); 254disable_pci: 255 pci_disable_device(pdev); 256done: 257 kfree(sd); 258 return ret; 259} 260 261static void sdv_gpio_remove(struct pci_dev *pdev) 262{ 263 struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev); 264 265 free_irq(pdev->irq, sd); 266 irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); 267 268 gpiochip_remove(&sd->bgpio.gc); 269 pci_release_region(pdev, GPIO_BAR); 270 iounmap(sd->gpio_pub_base); 271 pci_disable_device(pdev); 272 kfree(sd); 273} 274 275static const struct pci_device_id sdv_gpio_pci_ids[] = { 276 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) }, 277 { 0, }, 278}; 279 280static struct pci_driver sdv_gpio_driver = { 281 .name = DRV_NAME, 282 .id_table = sdv_gpio_pci_ids, 283 .probe = sdv_gpio_probe, 284 .remove = sdv_gpio_remove, 285}; 286 287module_pci_driver(sdv_gpio_driver); 288 289MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>"); 290MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); 291MODULE_LICENSE("GPL v2"); 292