Blame view
drivers/gpio/gpio-timberdale.c
7.52 KB
35570ac60 gpio: add GPIO dr... |
1 |
/* |
c103de240 gpio: reorganize ... |
2 |
* Timberdale FPGA GPIO driver |
52ad90531 gpio: timberdale:... |
3 |
* Author: Mocean Laboratories |
35570ac60 gpio: add GPIO dr... |
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
* Copyright (c) 2009 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Supports: * Timberdale FPGA GPIO */ |
52ad90531 gpio: timberdale:... |
23 |
#include <linux/init.h> |
35570ac60 gpio: add GPIO dr... |
24 25 |
#include <linux/gpio.h> #include <linux/platform_device.h> |
e3cb91ce1 timbgpio: fix build |
26 |
#include <linux/irq.h> |
35570ac60 gpio: add GPIO dr... |
27 28 29 |
#include <linux/io.h> #include <linux/timb_gpio.h> #include <linux/interrupt.h> |
5a0e3ad6a include cleanup: ... |
30 |
#include <linux/slab.h> |
35570ac60 gpio: add GPIO dr... |
31 32 33 34 35 36 37 38 39 40 41 |
#define DRIVER_NAME "timb-gpio" #define TGPIOVAL 0x00 #define TGPIODIR 0x04 #define TGPIO_IER 0x08 #define TGPIO_ISR 0x0c #define TGPIO_IPR 0x10 #define TGPIO_ICR 0x14 #define TGPIO_FLR 0x18 #define TGPIO_LVR 0x1c |
8c35c89aa timbgpio: add sup... |
42 43 |
#define TGPIO_VER 0x20 #define TGPIO_BFLR 0x24 |
35570ac60 gpio: add GPIO dr... |
44 45 46 47 48 49 |
struct timbgpio { void __iomem *membase; spinlock_t lock; /* mutual exclusion */ struct gpio_chip gpio; int irq_base; |
76d800a5b gpio: timbgpio: u... |
50 |
unsigned long last_ier; |
35570ac60 gpio: add GPIO dr... |
51 52 53 54 55 |
}; static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, unsigned offset, bool enabled) { |
92a41e2f7 gpio: timberdale:... |
56 |
struct timbgpio *tgpio = gpiochip_get_data(gpio); |
35570ac60 gpio: add GPIO dr... |
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
u32 reg; spin_lock(&tgpio->lock); reg = ioread32(tgpio->membase + offset); if (enabled) reg |= (1 << index); else reg &= ~(1 << index); iowrite32(reg, tgpio->membase + offset); spin_unlock(&tgpio->lock); return 0; } static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { return timbgpio_update_bit(gpio, nr, TGPIODIR, true); } static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr) { |
92a41e2f7 gpio: timberdale:... |
80 |
struct timbgpio *tgpio = gpiochip_get_data(gpio); |
35570ac60 gpio: add GPIO dr... |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
u32 value; value = ioread32(tgpio->membase + TGPIOVAL); return (value & (1 << nr)) ? 1 : 0; } static int timbgpio_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { return timbgpio_update_bit(gpio, nr, TGPIODIR, false); } static void timbgpio_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) { timbgpio_update_bit(gpio, nr, TGPIOVAL, val != 0); } static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset) { |
92a41e2f7 gpio: timberdale:... |
101 |
struct timbgpio *tgpio = gpiochip_get_data(gpio); |
35570ac60 gpio: add GPIO dr... |
102 103 104 105 106 107 108 109 110 111 |
if (tgpio->irq_base <= 0) return -EINVAL; return tgpio->irq_base + offset; } /* * GPIO IRQ */ |
a1f5f22ad gpio: timbgpio: i... |
112 |
static void timbgpio_irq_disable(struct irq_data *d) |
35570ac60 gpio: add GPIO dr... |
113 |
{ |
a1f5f22ad gpio: timbgpio: i... |
114 115 |
struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); int offset = d->irq - tgpio->irq_base; |
76d800a5b gpio: timbgpio: u... |
116 |
unsigned long flags; |
35570ac60 gpio: add GPIO dr... |
117 |
|
76d800a5b gpio: timbgpio: u... |
118 |
spin_lock_irqsave(&tgpio->lock, flags); |
d79550a7b gpio-timberdale: ... |
119 |
tgpio->last_ier &= ~(1UL << offset); |
76d800a5b gpio: timbgpio: u... |
120 121 |
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); spin_unlock_irqrestore(&tgpio->lock, flags); |
35570ac60 gpio: add GPIO dr... |
122 |
} |
a1f5f22ad gpio: timbgpio: i... |
123 |
static void timbgpio_irq_enable(struct irq_data *d) |
35570ac60 gpio: add GPIO dr... |
124 |
{ |
a1f5f22ad gpio: timbgpio: i... |
125 126 |
struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); int offset = d->irq - tgpio->irq_base; |
76d800a5b gpio: timbgpio: u... |
127 |
unsigned long flags; |
35570ac60 gpio: add GPIO dr... |
128 |
|
76d800a5b gpio: timbgpio: u... |
129 |
spin_lock_irqsave(&tgpio->lock, flags); |
d79550a7b gpio-timberdale: ... |
130 |
tgpio->last_ier |= 1UL << offset; |
76d800a5b gpio: timbgpio: u... |
131 132 |
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); spin_unlock_irqrestore(&tgpio->lock, flags); |
35570ac60 gpio: add GPIO dr... |
133 |
} |
a1f5f22ad gpio: timbgpio: i... |
134 |
static int timbgpio_irq_type(struct irq_data *d, unsigned trigger) |
35570ac60 gpio: add GPIO dr... |
135 |
{ |
a1f5f22ad gpio: timbgpio: i... |
136 137 |
struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); int offset = d->irq - tgpio->irq_base; |
35570ac60 gpio: add GPIO dr... |
138 |
unsigned long flags; |
8c35c89aa timbgpio: add sup... |
139 140 |
u32 lvr, flr, bflr = 0; u32 ver; |
2a481800c drivers/gpio/timb... |
141 |
int ret = 0; |
35570ac60 gpio: add GPIO dr... |
142 143 144 |
if (offset < 0 || offset > tgpio->gpio.ngpio) return -EINVAL; |
8c35c89aa timbgpio: add sup... |
145 |
ver = ioread32(tgpio->membase + TGPIO_VER); |
35570ac60 gpio: add GPIO dr... |
146 147 148 149 |
spin_lock_irqsave(&tgpio->lock, flags); lvr = ioread32(tgpio->membase + TGPIO_LVR); flr = ioread32(tgpio->membase + TGPIO_FLR); |
8c35c89aa timbgpio: add sup... |
150 151 |
if (ver > 2) bflr = ioread32(tgpio->membase + TGPIO_BFLR); |
35570ac60 gpio: add GPIO dr... |
152 153 |
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { |
8c35c89aa timbgpio: add sup... |
154 |
bflr &= ~(1 << offset); |
35570ac60 gpio: add GPIO dr... |
155 156 157 158 159 160 |
flr &= ~(1 << offset); if (trigger & IRQ_TYPE_LEVEL_HIGH) lvr |= 1 << offset; else lvr &= ~(1 << offset); } |
8c35c89aa timbgpio: add sup... |
161 |
if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { |
2a481800c drivers/gpio/timb... |
162 163 164 |
if (ver < 3) { ret = -EINVAL; goto out; |
8a29a4096 gpio: gpio-timber... |
165 |
} else { |
8c35c89aa timbgpio: add sup... |
166 167 168 169 170 |
flr |= 1 << offset; bflr |= 1 << offset; } } else { bflr &= ~(1 << offset); |
35570ac60 gpio: add GPIO dr... |
171 |
flr |= 1 << offset; |
35570ac60 gpio: add GPIO dr... |
172 |
if (trigger & IRQ_TYPE_EDGE_FALLING) |
35570ac60 gpio: add GPIO dr... |
173 |
lvr &= ~(1 << offset); |
8c35c89aa timbgpio: add sup... |
174 175 |
else lvr |= 1 << offset; |
35570ac60 gpio: add GPIO dr... |
176 177 178 179 |
} iowrite32(lvr, tgpio->membase + TGPIO_LVR); iowrite32(flr, tgpio->membase + TGPIO_FLR); |
8c35c89aa timbgpio: add sup... |
180 181 |
if (ver > 2) iowrite32(bflr, tgpio->membase + TGPIO_BFLR); |
35570ac60 gpio: add GPIO dr... |
182 |
iowrite32(1 << offset, tgpio->membase + TGPIO_ICR); |
35570ac60 gpio: add GPIO dr... |
183 |
|
2a481800c drivers/gpio/timb... |
184 185 186 |
out: spin_unlock_irqrestore(&tgpio->lock, flags); return ret; |
35570ac60 gpio: add GPIO dr... |
187 |
} |
bd0b9ac40 genirq: Remove ir... |
188 |
static void timbgpio_irq(struct irq_desc *desc) |
35570ac60 gpio: add GPIO dr... |
189 |
{ |
476f8b4c9 gpio: Use irq_des... |
190 191 |
struct timbgpio *tgpio = irq_desc_get_handler_data(desc); struct irq_data *data = irq_desc_get_irq_data(desc); |
35570ac60 gpio: add GPIO dr... |
192 193 |
unsigned long ipr; int offset; |
476f8b4c9 gpio: Use irq_des... |
194 |
data->chip->irq_ack(data); |
35570ac60 gpio: add GPIO dr... |
195 196 |
ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); |
76d800a5b gpio: timbgpio: u... |
197 198 199 200 201 |
/* * Some versions of the hardware trash the IER register if more than * one interrupt is received simultaneously. */ iowrite32(0, tgpio->membase + TGPIO_IER); |
984b3f574 bitops: rename fo... |
202 |
for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio) |
35570ac60 gpio: add GPIO dr... |
203 |
generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset)); |
76d800a5b gpio: timbgpio: u... |
204 205 |
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER); |
35570ac60 gpio: add GPIO dr... |
206 207 208 209 |
} static struct irq_chip timbgpio_irqchip = { .name = "GPIO", |
a1f5f22ad gpio: timbgpio: i... |
210 211 212 |
.irq_enable = timbgpio_irq_enable, .irq_disable = timbgpio_irq_disable, .irq_set_type = timbgpio_irq_type, |
35570ac60 gpio: add GPIO dr... |
213 |
}; |
3836309d9 gpio: remove use ... |
214 |
static int timbgpio_probe(struct platform_device *pdev) |
35570ac60 gpio: add GPIO dr... |
215 216 |
{ int err, i; |
0ed3398ed gpio: timberdale:... |
217 |
struct device *dev = &pdev->dev; |
35570ac60 gpio: add GPIO dr... |
218 219 220 |
struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; |
e56aee189 gpio: use dev_get... |
221 |
struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); |
35570ac60 gpio: add GPIO dr... |
222 223 224 |
int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { |
0ed3398ed gpio: timberdale:... |
225 226 227 |
dev_err(dev, "Invalid platform data "); return -EINVAL; |
35570ac60 gpio: add GPIO dr... |
228 |
} |
0ed3398ed gpio: timberdale:... |
229 |
tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL); |
35570ac60 gpio: add GPIO dr... |
230 |
if (!tgpio) { |
0ed3398ed gpio: timberdale:... |
231 232 233 |
dev_err(dev, "Memory alloc failed "); return -EINVAL; |
35570ac60 gpio: add GPIO dr... |
234 235 236 237 |
} tgpio->irq_base = pdata->irq_base; spin_lock_init(&tgpio->lock); |
fa283db76 gpio: timberdale:... |
238 239 240 241 |
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); tgpio->membase = devm_ioremap_resource(dev, iomem); if (IS_ERR(tgpio->membase)) return PTR_ERR(tgpio->membase); |
35570ac60 gpio: add GPIO dr... |
242 243 244 245 246 |
gc = &tgpio->gpio; gc->label = dev_name(&pdev->dev); gc->owner = THIS_MODULE; |
58383c784 gpio: change memb... |
247 |
gc->parent = &pdev->dev; |
35570ac60 gpio: add GPIO dr... |
248 249 250 251 252 253 254 255 |
gc->direction_input = timbgpio_gpio_direction_input; gc->get = timbgpio_gpio_get; gc->direction_output = timbgpio_gpio_direction_output; gc->set = timbgpio_gpio_set; gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL; gc->dbg_show = NULL; gc->base = pdata->gpio_base; gc->ngpio = pdata->nr_pins; |
9fb1f39eb gpio/pinctrl: mak... |
256 |
gc->can_sleep = false; |
35570ac60 gpio: add GPIO dr... |
257 |
|
43fad8322 gpio: timberdale ... |
258 |
err = devm_gpiochip_add_data(&pdev->dev, gc, tgpio); |
35570ac60 gpio: add GPIO dr... |
259 |
if (err) |
0ed3398ed gpio: timberdale:... |
260 |
return err; |
35570ac60 gpio: add GPIO dr... |
261 262 263 264 265 266 267 268 269 270 |
platform_set_drvdata(pdev, tgpio); /* make sure to disable interrupts */ iowrite32(0x0, tgpio->membase + TGPIO_IER); if (irq < 0 || tgpio->irq_base <= 0) return 0; for (i = 0; i < pdata->nr_pins; i++) { |
e5428a682 gpio: drop users ... |
271 272 |
irq_set_chip_and_handler(tgpio->irq_base + i, &timbgpio_irqchip, handle_simple_irq); |
b51804bcf gpio: Cleanup gen... |
273 |
irq_set_chip_data(tgpio->irq_base + i, tgpio); |
23393d49f gpio: kill off se... |
274 |
irq_clear_status_flags(tgpio->irq_base + i, IRQ_NOREQUEST | IRQ_NOPROBE); |
35570ac60 gpio: add GPIO dr... |
275 |
} |
8a52211ad gpio/timberdale: ... |
276 |
irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio); |
35570ac60 gpio: add GPIO dr... |
277 278 |
return 0; |
35570ac60 gpio: add GPIO dr... |
279 |
} |
35570ac60 gpio: add GPIO dr... |
280 281 |
static struct platform_driver timbgpio_platform_driver = { .driver = { |
52ad90531 gpio: timberdale:... |
282 283 |
.name = DRIVER_NAME, .suppress_bind_attrs = true, |
35570ac60 gpio: add GPIO dr... |
284 285 |
}, .probe = timbgpio_probe, |
35570ac60 gpio: add GPIO dr... |
286 287 288 |
}; /*--------------------------------------------------------------------------*/ |
52ad90531 gpio: timberdale:... |
289 |
builtin_platform_driver(timbgpio_platform_driver); |