brintos

brintos / linux-shallow public Read only

0
0
Text · 6.8 KiB · fad9797 Raw
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