289 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Timberdale FPGA GPIO driver4 * Author: Mocean Laboratories5 * Copyright (c) 2009 Intel Corporation6 */7 8/* Supports:9 * Timberdale FPGA GPIO10 */11 12#include <linux/init.h>13#include <linux/gpio/driver.h>14#include <linux/platform_device.h>15#include <linux/irq.h>16#include <linux/io.h>17#include <linux/timb_gpio.h>18#include <linux/interrupt.h>19#include <linux/slab.h>20 21#define DRIVER_NAME "timb-gpio"22 23#define TGPIOVAL 0x0024#define TGPIODIR 0x0425#define TGPIO_IER 0x0826#define TGPIO_ISR 0x0c27#define TGPIO_IPR 0x1028#define TGPIO_ICR 0x1429#define TGPIO_FLR 0x1830#define TGPIO_LVR 0x1c31#define TGPIO_VER 0x2032#define TGPIO_BFLR 0x2433 34struct timbgpio {35 void __iomem *membase;36 spinlock_t lock; /* mutual exclusion */37 struct gpio_chip gpio;38 int irq_base;39 unsigned long last_ier;40};41 42static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,43 unsigned offset, bool enabled)44{45 struct timbgpio *tgpio = gpiochip_get_data(gpio);46 unsigned long flags;47 u32 reg;48 49 spin_lock_irqsave(&tgpio->lock, flags);50 reg = ioread32(tgpio->membase + offset);51 52 if (enabled)53 reg |= (1 << index);54 else55 reg &= ~(1 << index);56 57 iowrite32(reg, tgpio->membase + offset);58 spin_unlock_irqrestore(&tgpio->lock, flags);59 60 return 0;61}62 63static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)64{65 return timbgpio_update_bit(gpio, nr, TGPIODIR, true);66}67 68static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)69{70 struct timbgpio *tgpio = gpiochip_get_data(gpio);71 u32 value;72 73 value = ioread32(tgpio->membase + TGPIOVAL);74 return (value & (1 << nr)) ? 1 : 0;75}76 77static int timbgpio_gpio_direction_output(struct gpio_chip *gpio,78 unsigned nr, int val)79{80 return timbgpio_update_bit(gpio, nr, TGPIODIR, false);81}82 83static void timbgpio_gpio_set(struct gpio_chip *gpio,84 unsigned nr, int val)85{86 timbgpio_update_bit(gpio, nr, TGPIOVAL, val != 0);87}88 89static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset)90{91 struct timbgpio *tgpio = gpiochip_get_data(gpio);92 93 if (tgpio->irq_base <= 0)94 return -EINVAL;95 96 return tgpio->irq_base + offset;97}98 99/*100 * GPIO IRQ101 */102static void timbgpio_irq_disable(struct irq_data *d)103{104 struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);105 int offset = d->irq - tgpio->irq_base;106 unsigned long flags;107 108 spin_lock_irqsave(&tgpio->lock, flags);109 tgpio->last_ier &= ~(1UL << offset);110 iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);111 spin_unlock_irqrestore(&tgpio->lock, flags);112}113 114static void timbgpio_irq_enable(struct irq_data *d)115{116 struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);117 int offset = d->irq - tgpio->irq_base;118 unsigned long flags;119 120 spin_lock_irqsave(&tgpio->lock, flags);121 tgpio->last_ier |= 1UL << offset;122 iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);123 spin_unlock_irqrestore(&tgpio->lock, flags);124}125 126static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)127{128 struct timbgpio *tgpio = irq_data_get_irq_chip_data(d);129 int offset = d->irq - tgpio->irq_base;130 unsigned long flags;131 u32 lvr, flr, bflr = 0;132 u32 ver;133 int ret = 0;134 135 if (offset < 0 || offset > tgpio->gpio.ngpio)136 return -EINVAL;137 138 ver = ioread32(tgpio->membase + TGPIO_VER);139 140 spin_lock_irqsave(&tgpio->lock, flags);141 142 lvr = ioread32(tgpio->membase + TGPIO_LVR);143 flr = ioread32(tgpio->membase + TGPIO_FLR);144 if (ver > 2)145 bflr = ioread32(tgpio->membase + TGPIO_BFLR);146 147 if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {148 bflr &= ~(1 << offset);149 flr &= ~(1 << offset);150 if (trigger & IRQ_TYPE_LEVEL_HIGH)151 lvr |= 1 << offset;152 else153 lvr &= ~(1 << offset);154 }155 156 if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {157 if (ver < 3) {158 ret = -EINVAL;159 goto out;160 } else {161 flr |= 1 << offset;162 bflr |= 1 << offset;163 }164 } else {165 bflr &= ~(1 << offset);166 flr |= 1 << offset;167 if (trigger & IRQ_TYPE_EDGE_FALLING)168 lvr &= ~(1 << offset);169 else170 lvr |= 1 << offset;171 }172 173 iowrite32(lvr, tgpio->membase + TGPIO_LVR);174 iowrite32(flr, tgpio->membase + TGPIO_FLR);175 if (ver > 2)176 iowrite32(bflr, tgpio->membase + TGPIO_BFLR);177 178 iowrite32(1 << offset, tgpio->membase + TGPIO_ICR);179 180out:181 spin_unlock_irqrestore(&tgpio->lock, flags);182 return ret;183}184 185static void timbgpio_irq(struct irq_desc *desc)186{187 struct timbgpio *tgpio = irq_desc_get_handler_data(desc);188 struct irq_data *data = irq_desc_get_irq_data(desc);189 unsigned long ipr;190 int offset;191 192 data->chip->irq_ack(data);193 ipr = ioread32(tgpio->membase + TGPIO_IPR);194 iowrite32(ipr, tgpio->membase + TGPIO_ICR);195 196 /*197 * Some versions of the hardware trash the IER register if more than198 * one interrupt is received simultaneously.199 */200 iowrite32(0, tgpio->membase + TGPIO_IER);201 202 for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio)203 generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));204 205 iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);206}207 208static struct irq_chip timbgpio_irqchip = {209 .name = "GPIO",210 .irq_enable = timbgpio_irq_enable,211 .irq_disable = timbgpio_irq_disable,212 .irq_set_type = timbgpio_irq_type,213};214 215static int timbgpio_probe(struct platform_device *pdev)216{217 int err, i;218 struct device *dev = &pdev->dev;219 struct gpio_chip *gc;220 struct timbgpio *tgpio;221 struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);222 int irq = platform_get_irq(pdev, 0);223 224 if (!pdata || pdata->nr_pins > 32) {225 dev_err(dev, "Invalid platform data\n");226 return -EINVAL;227 }228 229 tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL);230 if (!tgpio)231 return -EINVAL;232 233 tgpio->irq_base = pdata->irq_base;234 235 spin_lock_init(&tgpio->lock);236 237 tgpio->membase = devm_platform_ioremap_resource(pdev, 0);238 if (IS_ERR(tgpio->membase))239 return PTR_ERR(tgpio->membase);240 241 gc = &tgpio->gpio;242 243 gc->label = dev_name(&pdev->dev);244 gc->owner = THIS_MODULE;245 gc->parent = &pdev->dev;246 gc->direction_input = timbgpio_gpio_direction_input;247 gc->get = timbgpio_gpio_get;248 gc->direction_output = timbgpio_gpio_direction_output;249 gc->set = timbgpio_gpio_set;250 gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL;251 gc->dbg_show = NULL;252 gc->base = pdata->gpio_base;253 gc->ngpio = pdata->nr_pins;254 gc->can_sleep = false;255 256 err = devm_gpiochip_add_data(&pdev->dev, gc, tgpio);257 if (err)258 return err;259 260 /* make sure to disable interrupts */261 iowrite32(0x0, tgpio->membase + TGPIO_IER);262 263 if (irq < 0 || tgpio->irq_base <= 0)264 return 0;265 266 for (i = 0; i < pdata->nr_pins; i++) {267 irq_set_chip_and_handler(tgpio->irq_base + i,268 &timbgpio_irqchip, handle_simple_irq);269 irq_set_chip_data(tgpio->irq_base + i, tgpio);270 irq_clear_status_flags(tgpio->irq_base + i, IRQ_NOREQUEST | IRQ_NOPROBE);271 }272 273 irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio);274 275 return 0;276}277 278static struct platform_driver timbgpio_platform_driver = {279 .driver = {280 .name = DRIVER_NAME,281 .suppress_bind_attrs = true,282 },283 .probe = timbgpio_probe,284};285 286/*--------------------------------------------------------------------------*/287 288builtin_platform_driver(timbgpio_platform_driver);289