aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorTomoya MORINAGA <tomoya-linux@dsn.okisemi.com>2011-08-05 00:04:21 -0400
committerGrant Likely <grant.likely@secretlab.ca>2011-10-05 13:57:04 -0400
commit54be566317b6aece2389a95bb19ea209af9359be (patch)
treec8b89ac9809473fe2f39068e41f89a4f89fecc0b /drivers/gpio
parent45d198c4cf3a9a751b734eb32426b6de4631ef2e (diff)
gpio-ml-ioh: Support interrupt function
Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig1
-rw-r--r--drivers/gpio/gpio-ml-ioh.c209
2 files changed, 207 insertions, 3 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d539efd96d4b..04499c19e986 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -402,6 +402,7 @@ config GPIO_PCH
402config GPIO_ML_IOH 402config GPIO_ML_IOH
403 tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" 403 tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
404 depends on PCI 404 depends on PCI
405 select GENERIC_IRQ_CHIP
405 help 406 help
406 ML7213 is companion chip for Intel Atom E6xx series. 407 ML7213 is companion chip for Intel Atom E6xx series.
407 This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output 408 This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 655e55c55e02..4fab37bf564d 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -18,6 +18,17 @@
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/pci.h> 19#include <linux/pci.h>
20#include <linux/gpio.h> 20#include <linux/gpio.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23
24#define IOH_EDGE_FALLING 0
25#define IOH_EDGE_RISING BIT(0)
26#define IOH_LEVEL_L BIT(1)
27#define IOH_LEVEL_H (BIT(0) | BIT(1))
28#define IOH_EDGE_BOTH BIT(2)
29#define IOH_IM_MASK (BIT(0) | BIT(1) | BIT(2))
30
31#define IOH_IRQ_BASE 0
21 32
22#define PCI_VENDOR_ID_ROHM 0x10DB 33#define PCI_VENDOR_ID_ROHM 0x10DB
23 34
@@ -46,12 +57,20 @@ struct ioh_regs {
46 57
47/** 58/**
48 * struct ioh_gpio_reg_data - The register store data. 59 * struct ioh_gpio_reg_data - The register store data.
60 * @ien_reg To store contents of interrupt enable register.
61 * @imask_reg: To store contents of interrupt mask regist
49 * @po_reg: To store contents of PO register. 62 * @po_reg: To store contents of PO register.
50 * @pm_reg: To store contents of PM register. 63 * @pm_reg: To store contents of PM register.
64 * @im0_reg: To store contents of interrupt mode regist0
65 * @im1_reg: To store contents of interrupt mode regist1
51 */ 66 */
52struct ioh_gpio_reg_data { 67struct ioh_gpio_reg_data {
68 u32 ien_reg;
69 u32 imask_reg;
53 u32 po_reg; 70 u32 po_reg;
54 u32 pm_reg; 71 u32 pm_reg;
72 u32 im0_reg;
73 u32 im1_reg;
55}; 74};
56 75
57/** 76/**
@@ -63,6 +82,9 @@ struct ioh_gpio_reg_data {
63 * @ioh_gpio_reg: Memory mapped Register data is saved here 82 * @ioh_gpio_reg: Memory mapped Register data is saved here
64 * when suspend. 83 * when suspend.
65 * @ch: Indicate GPIO channel 84 * @ch: Indicate GPIO channel
85 * @irq_base: Save base of IRQ number for interrupt
86 * @spinlock: Used for register access protection in
87 * interrupt context ioh_irq_type and PM;
66 */ 88 */
67struct ioh_gpio { 89struct ioh_gpio {
68 void __iomem *base; 90 void __iomem *base;
@@ -72,6 +94,8 @@ struct ioh_gpio {
72 struct ioh_gpio_reg_data ioh_gpio_reg; 94 struct ioh_gpio_reg_data ioh_gpio_reg;
73 struct mutex lock; 95 struct mutex lock;
74 int ch; 96 int ch;
97 int irq_base;
98 spinlock_t spinlock;
75}; 99};
76 100
77static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12}; 101static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
@@ -147,6 +171,10 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
147{ 171{
148 chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po); 172 chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po);
149 chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm); 173 chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm);
174 chip->ioh_gpio_reg.ien_reg = ioread32(&chip->reg->regs[chip->ch].ien);
175 chip->ioh_gpio_reg.imask_reg = ioread32(&chip->reg->regs[chip->ch].imask);
176 chip->ioh_gpio_reg.im0_reg = ioread32(&chip->reg->regs[chip->ch].im_0);
177 chip->ioh_gpio_reg.im1_reg = ioread32(&chip->reg->regs[chip->ch].im_1);
150} 178}
151 179
152/* 180/*
@@ -154,13 +182,21 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
154 */ 182 */
155static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) 183static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
156{ 184{
157 /* to store contents of PO register */
158 iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po); 185 iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po);
159 /* to store contents of PM register */
160 iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm); 186 iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
187 iowrite32(chip->ioh_gpio_reg.ien_reg, &chip->reg->regs[chip->ch].ien);
188 iowrite32(chip->ioh_gpio_reg.imask_reg, &chip->reg->regs[chip->ch].imask);
189 iowrite32(chip->ioh_gpio_reg.im0_reg, &chip->reg->regs[chip->ch].im_0);
190 iowrite32(chip->ioh_gpio_reg.im1_reg, &chip->reg->regs[chip->ch].im_1);
161} 191}
162#endif 192#endif
163 193
194static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
195{
196 struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
197 return chip->irq_base + offset;
198}
199
164static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) 200static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
165{ 201{
166 struct gpio_chip *gpio = &chip->gpio; 202 struct gpio_chip *gpio = &chip->gpio;
@@ -175,16 +211,148 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
175 gpio->base = -1; 211 gpio->base = -1;
176 gpio->ngpio = num_port; 212 gpio->ngpio = num_port;
177 gpio->can_sleep = 0; 213 gpio->can_sleep = 0;
214 gpio->to_irq = ioh_gpio_to_irq;
215}
216
217static int ioh_irq_type(struct irq_data *d, unsigned int type)
218{
219 u32 im;
220 u32 *im_reg;
221 u32 ien;
222 u32 im_pos;
223 int ch;
224 unsigned long flags;
225 u32 val;
226 int irq = d->irq;
227 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
228 struct ioh_gpio *chip = gc->private;
229
230 ch = irq - chip->irq_base;
231 if (irq <= chip->irq_base + 7) {
232 im_reg = &chip->reg->regs[chip->ch].im_0;
233 im_pos = ch;
234 } else {
235 im_reg = &chip->reg->regs[chip->ch].im_1;
236 im_pos = ch - 8;
237 }
238 dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
239 __func__, irq, type, ch, im_pos, type);
240
241 spin_lock_irqsave(&chip->spinlock, flags);
242
243 switch (type) {
244 case IRQ_TYPE_EDGE_RISING:
245 val = IOH_EDGE_RISING;
246 break;
247 case IRQ_TYPE_EDGE_FALLING:
248 val = IOH_EDGE_FALLING;
249 break;
250 case IRQ_TYPE_EDGE_BOTH:
251 val = IOH_EDGE_BOTH;
252 break;
253 case IRQ_TYPE_LEVEL_HIGH:
254 val = IOH_LEVEL_H;
255 break;
256 case IRQ_TYPE_LEVEL_LOW:
257 val = IOH_LEVEL_L;
258 break;
259 case IRQ_TYPE_PROBE:
260 goto end;
261 default:
262 dev_warn(chip->dev, "%s: unknown type(%dd)",
263 __func__, type);
264 goto end;
265 }
266
267 /* Set interrupt mode */
268 im = ioread32(im_reg) & ~(IOH_IM_MASK << (im_pos * 4));
269 iowrite32(im | (val << (im_pos * 4)), im_reg);
270
271 /* iclr */
272 iowrite32(BIT(ch), &chip->reg->regs[chip->ch].iclr);
273
274 /* IMASKCLR */
275 iowrite32(BIT(ch), &chip->reg->regs[chip->ch].imaskclr);
276
277 /* Enable interrupt */
278 ien = ioread32(&chip->reg->regs[chip->ch].ien);
279 iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
280end:
281 spin_unlock_irqrestore(&chip->spinlock, flags);
282
283 return 0;
284}
285
286static void ioh_irq_unmask(struct irq_data *d)
287{
288 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
289 struct ioh_gpio *chip = gc->private;
290
291 iowrite32(1 << (d->irq - chip->irq_base),
292 &chip->reg->regs[chip->ch].imaskclr);
293}
294
295static void ioh_irq_mask(struct irq_data *d)
296{
297 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
298 struct ioh_gpio *chip = gc->private;
299
300 iowrite32(1 << (d->irq - chip->irq_base),
301 &chip->reg->regs[chip->ch].imask);
302}
303
304static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
305{
306 struct ioh_gpio *chip = dev_id;
307 u32 reg_val;
308 int i, j;
309 int ret = IRQ_NONE;
310
311 for (i = 0; i < 8; i++) {
312 reg_val = ioread32(&chip->reg->regs[i].istatus);
313 for (j = 0; j < num_ports[i]; j++) {
314 if (reg_val & BIT(j)) {
315 dev_dbg(chip->dev,
316 "%s:[%d]:irq=%d status=0x%x\n",
317 __func__, j, irq, reg_val);
318 iowrite32(BIT(j),
319 &chip->reg->regs[chip->ch].iclr);
320 generic_handle_irq(chip->irq_base + j);
321 ret = IRQ_HANDLED;
322 }
323 }
324 }
325 return ret;
326}
327
328static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
329 unsigned int irq_start, unsigned int num)
330{
331 struct irq_chip_generic *gc;
332 struct irq_chip_type *ct;
333
334 gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base,
335 handle_simple_irq);
336 gc->private = chip;
337 ct = gc->chip_types;
338
339 ct->chip.irq_mask = ioh_irq_mask;
340 ct->chip.irq_unmask = ioh_irq_unmask;
341 ct->chip.irq_set_type = ioh_irq_type;
342
343 irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
344 IRQ_NOREQUEST | IRQ_NOPROBE, 0);
178} 345}
179 346
180static int __devinit ioh_gpio_probe(struct pci_dev *pdev, 347static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
181 const struct pci_device_id *id) 348 const struct pci_device_id *id)
182{ 349{
183 int ret; 350 int ret;
184 int i; 351 int i, j;
185 struct ioh_gpio *chip; 352 struct ioh_gpio *chip;
186 void __iomem *base; 353 void __iomem *base;
187 void __iomem *chip_save; 354 void __iomem *chip_save;
355 int irq_base;
188 356
189 ret = pci_enable_device(pdev); 357 ret = pci_enable_device(pdev);
190 if (ret) { 358 if (ret) {
@@ -228,10 +396,41 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
228 } 396 }
229 397
230 chip = chip_save; 398 chip = chip_save;
399 for (j = 0; j < 8; j++, chip++) {
400 irq_base = irq_alloc_descs(-1, IOH_IRQ_BASE, num_ports[j],
401 GFP_KERNEL);
402 if (irq_base < 0) {
403 dev_warn(&pdev->dev,
404 "ml_ioh_gpio: Failed to get IRQ base num\n");
405 chip->irq_base = -1;
406 goto err_irq_alloc_descs;
407 }
408 chip->irq_base = irq_base;
409 ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]);
410 }
411
412 chip = chip_save;
413 ret = request_irq(pdev->irq, ioh_gpio_handler,
414 IRQF_SHARED, KBUILD_MODNAME, chip);
415 if (ret != 0) {
416 dev_err(&pdev->dev,
417 "%s request_irq failed\n", __func__);
418 goto err_request_irq;
419 }
420
231 pci_set_drvdata(pdev, chip); 421 pci_set_drvdata(pdev, chip);
232 422
233 return 0; 423 return 0;
234 424
425err_request_irq:
426 chip = chip_save;
427err_irq_alloc_descs:
428 while (--j >= 0) {
429 chip--;
430 irq_free_descs(chip->irq_base, num_ports[j]);
431 }
432
433 chip = chip_save;
235err_gpiochip_add: 434err_gpiochip_add:
236 while (--i >= 0) { 435 while (--i >= 0) {
237 chip--; 436 chip--;
@@ -264,7 +463,11 @@ static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
264 void __iomem *chip_save; 463 void __iomem *chip_save;
265 464
266 chip_save = chip; 465 chip_save = chip;
466
467 free_irq(pdev->irq, chip);
468
267 for (i = 0; i < 8; i++, chip++) { 469 for (i = 0; i < 8; i++, chip++) {
470 irq_free_descs(chip->irq_base, num_ports[i]);
268 err = gpiochip_remove(&chip->gpio); 471 err = gpiochip_remove(&chip->gpio);
269 if (err) 472 if (err)
270 dev_err(&pdev->dev, "Failed gpiochip_remove\n"); 473 dev_err(&pdev->dev, "Failed gpiochip_remove\n");