Blame view

drivers/irqchip/irq-sa11x0.c 3.89 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
85e6f0978   Dmitry Eremin-Solenikov   ARM: 8367/1: sa11...
2
   * Copyright (C) 2015 Dmitry Eremin-Solenikov
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   * Copyright (C) 1999-2001 Nicolas Pitre
   *
85e6f0978   Dmitry Eremin-Solenikov   ARM: 8367/1: sa11...
5
   * Generic IRQ handling for the SA11x0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
   *
   * 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.
   */
  #include <linux/init.h>
  #include <linux/module.h>
119c641c9   Thomas Gleixner   [ARM] 3698/1: ARM...
13
  #include <linux/interrupt.h>
3169663ac   Russell King   ARM: sa11x0/pxa: ...
14
  #include <linux/io.h>
119c641c9   Thomas Gleixner   [ARM] 3698/1: ARM...
15
  #include <linux/irq.h>
1eca42b49   Dmitry Eremin-Solenikov   ARM: 8231/1: sa11...
16
  #include <linux/irqdomain.h>
905339807   Rafael J. Wysocki   ARM / SA1100: Use...
17
  #include <linux/syscore_ops.h>
85e6f0978   Dmitry Eremin-Solenikov   ARM: 8367/1: sa11...
18
  #include <linux/irqchip/irq-sa11x0.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

a657d7f67   Dmitry Eremin-Solenikov   ARM: 8362/1: sa11...
20
  #include <soc/sa1100/pwer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

affcab32e   Dmitry Eremin-Solenikov   ARM: 8227/1: sa11...
22
  #include <asm/exception.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
24
25
26
27
28
29
  #define ICIP	0x00  /* IC IRQ Pending reg. */
  #define ICMR	0x04  /* IC Mask Reg.        */
  #define ICLR	0x08  /* IC Level Reg.       */
  #define ICCR	0x0C  /* IC Control Reg.     */
  #define ICFP	0x10  /* IC FIQ Pending reg. */
  #define ICPR	0x20  /* IC Pending Reg.     */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
31
  static void __iomem *iobase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  
  /*
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
34
35
36
37
38
   * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
   * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm.
   */
  static void sa1100_mask_irq(struct irq_data *d)
  {
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
39
40
41
42
43
  	u32 reg;
  
  	reg = readl_relaxed(iobase + ICMR);
  	reg &= ~BIT(d->hwirq);
  	writel_relaxed(reg, iobase + ICMR);
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
44
45
46
47
  }
  
  static void sa1100_unmask_irq(struct irq_data *d)
  {
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
48
49
50
51
52
  	u32 reg;
  
  	reg = readl_relaxed(iobase + ICMR);
  	reg |= BIT(d->hwirq);
  	writel_relaxed(reg, iobase + ICMR);
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
53
  }
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
54
55
  static int sa1100_set_wake(struct irq_data *d, unsigned int on)
  {
a657d7f67   Dmitry Eremin-Solenikov   ARM: 8362/1: sa11...
56
  	return sa11x0_sc_set_wake(d->hwirq, on);
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  }
  
  static struct irq_chip sa1100_normal_chip = {
  	.name		= "SC",
  	.irq_ack	= sa1100_mask_irq,
  	.irq_mask	= sa1100_mask_irq,
  	.irq_unmask	= sa1100_unmask_irq,
  	.irq_set_wake	= sa1100_set_wake,
  };
  
  static int sa1100_normal_irqdomain_map(struct irq_domain *d,
  		unsigned int irq, irq_hw_number_t hwirq)
  {
  	irq_set_chip_and_handler(irq, &sa1100_normal_chip,
  				 handle_level_irq);
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
72
73
74
  
  	return 0;
  }
9827e8e55   Krzysztof Kozlowski   ARM: 8346/1: sa11...
75
  static const struct irq_domain_ops sa1100_normal_irqdomain_ops = {
ab71f99fd   Dmitry Eremin-Solenikov   ARM: 8234/1: sa11...
76
77
78
79
80
  	.map = sa1100_normal_irqdomain_map,
  	.xlate = irq_domain_xlate_onetwocell,
  };
  
  static struct irq_domain *sa1100_normal_irqdomain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
  static struct sa1100irq_state {
  	unsigned int	saved;
  	unsigned int	icmr;
  	unsigned int	iclr;
  	unsigned int	iccr;
  } sa1100irq_state;
905339807   Rafael J. Wysocki   ARM / SA1100: Use...
87
  static int sa1100irq_suspend(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
  {
  	struct sa1100irq_state *st = &sa1100irq_state;
  
  	st->saved = 1;
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
92
93
94
  	st->icmr = readl_relaxed(iobase + ICMR);
  	st->iclr = readl_relaxed(iobase + ICLR);
  	st->iccr = readl_relaxed(iobase + ICCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  
  	/*
  	 * Disable all GPIO-based interrupts.
  	 */
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
99
  	writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  	return 0;
  }
905339807   Rafael J. Wysocki   ARM / SA1100: Use...
103
  static void sa1100irq_resume(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
107
  {
  	struct sa1100irq_state *st = &sa1100irq_state;
  
  	if (st->saved) {
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
108
109
  		writel_relaxed(st->iccr, iobase + ICCR);
  		writel_relaxed(st->iclr, iobase + ICLR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110

60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
111
  		writel_relaxed(st->icmr, iobase + ICMR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
  }
905339807   Rafael J. Wysocki   ARM / SA1100: Use...
114
  static struct syscore_ops sa1100irq_syscore_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
  	.suspend	= sa1100irq_suspend,
  	.resume		= sa1100irq_resume,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  static int __init sa1100irq_init_devicefs(void)
  {
905339807   Rafael J. Wysocki   ARM / SA1100: Use...
120
121
  	register_syscore_ops(&sa1100irq_syscore_ops);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
  }
  
  device_initcall(sa1100irq_init_devicefs);
affcab32e   Dmitry Eremin-Solenikov   ARM: 8227/1: sa11...
125
126
127
128
129
130
  static asmlinkage void __exception_irq_entry
  sa1100_handle_irq(struct pt_regs *regs)
  {
  	uint32_t icip, icmr, mask;
  
  	do {
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
131
132
  		icip = readl_relaxed(iobase + ICIP);
  		icmr = readl_relaxed(iobase + ICMR);
affcab32e   Dmitry Eremin-Solenikov   ARM: 8227/1: sa11...
133
134
135
136
  		mask = icip & icmr;
  
  		if (mask == 0)
  			break;
364e38691   Dmitry Eremin-Solenikov   ARM: 8282/1: sa11...
137
138
  		handle_domain_irq(sa1100_normal_irqdomain,
  				ffs(mask) - 1, regs);
affcab32e   Dmitry Eremin-Solenikov   ARM: 8227/1: sa11...
139
140
  	} while (1);
  }
85e6f0978   Dmitry Eremin-Solenikov   ARM: 8367/1: sa11...
141
  void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  {
85e6f0978   Dmitry Eremin-Solenikov   ARM: 8367/1: sa11...
143
  	iobase = ioremap(io_start, SZ_64K);
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
144
145
  	if (WARN_ON(!iobase))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  
  	/* disable all IRQs */
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
148
  	writel_relaxed(0, iobase + ICMR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
  
  	/* all IRQs are IRQ, not FIQ */
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
151
  	writel_relaxed(0, iobase + ICLR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
  	/*
  	 * Whatever the doc says, this has to be set for the wait-on-irq
  	 * instruction to work... on a SA1100 rev 9 at least.
  	 */
60c06c4c6   Dmitry Eremin-Solenikov   ARM: 8363/1: sa11...
157
  	writel_relaxed(1, iobase + ICCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158

a82be3f0f   Dmitry Eremin-Solenikov   ARM: 8280/1: sa11...
159
  	sa1100_normal_irqdomain = irq_domain_add_simple(NULL,
85e6f0978   Dmitry Eremin-Solenikov   ARM: 8367/1: sa11...
160
  			32, irq_start,
83508093f   Dmitry Eremin-Solenikov   ARM: 8278/1: sa11...
161
  			&sa1100_normal_irqdomain_ops, NULL);
affcab32e   Dmitry Eremin-Solenikov   ARM: 8227/1: sa11...
162
  	set_handle_irq(sa1100_handle_irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  }