6
6
* Vadim V.Vlasov <vvlasov@dev.rtsoft.ru>
7
7
*/
8
8
9
+ #include <linux/bitmap.h>
9
10
#include <linux/bitops.h>
10
11
#include <linux/errno.h>
11
12
#include <linux/gpio/driver.h>
28
29
#define TQMX86_GPIIC 3 /* GPI Interrupt Configuration Register */
29
30
#define TQMX86_GPIIS 4 /* GPI Interrupt Status Register */
30
31
32
+ #define TQMX86_GPII_NONE 0
31
33
#define TQMX86_GPII_FALLING BIT(0)
32
34
#define TQMX86_GPII_RISING BIT(1)
35
+ /* Stored in irq_type as a trigger type, but not actually valid as a register
36
+ * value, so the name doesn't use "GPII"
37
+ */
38
+ #define TQMX86_INT_BOTH (BIT(0) | BIT(1))
33
39
#define TQMX86_GPII_MASK (BIT(0) | BIT(1))
34
40
#define TQMX86_GPII_BITS 2
41
+ /* Stored in irq_type with GPII bits */
42
+ #define TQMX86_INT_UNMASKED BIT(2)
35
43
36
44
struct tqmx86_gpio_data {
37
45
struct gpio_chip chip ;
38
46
void __iomem * io_base ;
39
47
int irq ;
48
+ /* Lock must be held for accessing output and irq_type fields */
40
49
raw_spinlock_t spinlock ;
50
+ DECLARE_BITMAP (output , TQMX86_NGPIO );
41
51
u8 irq_type [TQMX86_NGPI ];
42
52
};
43
53
@@ -64,15 +74,10 @@ static void tqmx86_gpio_set(struct gpio_chip *chip, unsigned int offset,
64
74
{
65
75
struct tqmx86_gpio_data * gpio = gpiochip_get_data (chip );
66
76
unsigned long flags ;
67
- u8 val ;
68
77
69
78
raw_spin_lock_irqsave (& gpio -> spinlock , flags );
70
- val = tqmx86_gpio_read (gpio , TQMX86_GPIOD );
71
- if (value )
72
- val |= BIT (offset );
73
- else
74
- val &= ~BIT (offset );
75
- tqmx86_gpio_write (gpio , val , TQMX86_GPIOD );
79
+ __assign_bit (offset , gpio -> output , value );
80
+ tqmx86_gpio_write (gpio , bitmap_get_value8 (gpio -> output , 0 ), TQMX86_GPIOD );
76
81
raw_spin_unlock_irqrestore (& gpio -> spinlock , flags );
77
82
}
78
83
@@ -107,21 +112,38 @@ static int tqmx86_gpio_get_direction(struct gpio_chip *chip,
107
112
return GPIO_LINE_DIRECTION_OUT ;
108
113
}
109
114
115
+ static void tqmx86_gpio_irq_config (struct tqmx86_gpio_data * gpio , int offset )
116
+ __must_hold (& gpio - > spinlock )
117
+ {
118
+ u8 type = TQMX86_GPII_NONE , gpiic ;
119
+
120
+ if (gpio -> irq_type [offset ] & TQMX86_INT_UNMASKED ) {
121
+ type = gpio -> irq_type [offset ] & TQMX86_GPII_MASK ;
122
+
123
+ if (type == TQMX86_INT_BOTH )
124
+ type = tqmx86_gpio_get (& gpio -> chip , offset + TQMX86_NGPO )
125
+ ? TQMX86_GPII_FALLING
126
+ : TQMX86_GPII_RISING ;
127
+ }
128
+
129
+ gpiic = tqmx86_gpio_read (gpio , TQMX86_GPIIC );
130
+ gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS ));
131
+ gpiic |= type << (offset * TQMX86_GPII_BITS );
132
+ tqmx86_gpio_write (gpio , gpiic , TQMX86_GPIIC );
133
+ }
134
+
110
135
static void tqmx86_gpio_irq_mask (struct irq_data * data )
111
136
{
112
137
unsigned int offset = (data -> hwirq - TQMX86_NGPO );
113
138
struct tqmx86_gpio_data * gpio = gpiochip_get_data (
114
139
irq_data_get_irq_chip_data (data ));
115
140
unsigned long flags ;
116
- u8 gpiic , mask ;
117
-
118
- mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS );
119
141
120
142
raw_spin_lock_irqsave (& gpio -> spinlock , flags );
121
- gpiic = tqmx86_gpio_read (gpio , TQMX86_GPIIC );
122
- gpiic &= ~mask ;
123
- tqmx86_gpio_write (gpio , gpiic , TQMX86_GPIIC );
143
+ gpio -> irq_type [offset ] &= ~TQMX86_INT_UNMASKED ;
144
+ tqmx86_gpio_irq_config (gpio , offset );
124
145
raw_spin_unlock_irqrestore (& gpio -> spinlock , flags );
146
+
125
147
gpiochip_disable_irq (& gpio -> chip , irqd_to_hwirq (data ));
126
148
}
127
149
@@ -131,16 +153,12 @@ static void tqmx86_gpio_irq_unmask(struct irq_data *data)
131
153
struct tqmx86_gpio_data * gpio = gpiochip_get_data (
132
154
irq_data_get_irq_chip_data (data ));
133
155
unsigned long flags ;
134
- u8 gpiic , mask ;
135
-
136
- mask = TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS );
137
156
138
157
gpiochip_enable_irq (& gpio -> chip , irqd_to_hwirq (data ));
158
+
139
159
raw_spin_lock_irqsave (& gpio -> spinlock , flags );
140
- gpiic = tqmx86_gpio_read (gpio , TQMX86_GPIIC );
141
- gpiic &= ~mask ;
142
- gpiic |= gpio -> irq_type [offset ] << (offset * TQMX86_GPII_BITS );
143
- tqmx86_gpio_write (gpio , gpiic , TQMX86_GPIIC );
160
+ gpio -> irq_type [offset ] |= TQMX86_INT_UNMASKED ;
161
+ tqmx86_gpio_irq_config (gpio , offset );
144
162
raw_spin_unlock_irqrestore (& gpio -> spinlock , flags );
145
163
}
146
164
@@ -151,7 +169,7 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
151
169
unsigned int offset = (data -> hwirq - TQMX86_NGPO );
152
170
unsigned int edge_type = type & IRQF_TRIGGER_MASK ;
153
171
unsigned long flags ;
154
- u8 new_type , gpiic ;
172
+ u8 new_type ;
155
173
156
174
switch (edge_type ) {
157
175
case IRQ_TYPE_EDGE_RISING :
@@ -161,19 +179,16 @@ static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)
161
179
new_type = TQMX86_GPII_FALLING ;
162
180
break ;
163
181
case IRQ_TYPE_EDGE_BOTH :
164
- new_type = TQMX86_GPII_FALLING | TQMX86_GPII_RISING ;
182
+ new_type = TQMX86_INT_BOTH ;
165
183
break ;
166
184
default :
167
185
return - EINVAL ; /* not supported */
168
186
}
169
187
170
- gpio -> irq_type [offset ] = new_type ;
171
-
172
188
raw_spin_lock_irqsave (& gpio -> spinlock , flags );
173
- gpiic = tqmx86_gpio_read (gpio , TQMX86_GPIIC );
174
- gpiic &= ~((TQMX86_GPII_MASK ) << (offset * TQMX86_GPII_BITS ));
175
- gpiic |= new_type << (offset * TQMX86_GPII_BITS );
176
- tqmx86_gpio_write (gpio , gpiic , TQMX86_GPIIC );
189
+ gpio -> irq_type [offset ] &= ~TQMX86_GPII_MASK ;
190
+ gpio -> irq_type [offset ] |= new_type ;
191
+ tqmx86_gpio_irq_config (gpio , offset );
177
192
raw_spin_unlock_irqrestore (& gpio -> spinlock , flags );
178
193
179
194
return 0 ;
@@ -184,8 +199,8 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
184
199
struct gpio_chip * chip = irq_desc_get_handler_data (desc );
185
200
struct tqmx86_gpio_data * gpio = gpiochip_get_data (chip );
186
201
struct irq_chip * irq_chip = irq_desc_get_chip (desc );
187
- unsigned long irq_bits ;
188
- int i = 0 ;
202
+ unsigned long irq_bits , flags ;
203
+ int i ;
189
204
u8 irq_status ;
190
205
191
206
chained_irq_enter (irq_chip , desc );
@@ -194,6 +209,34 @@ static void tqmx86_gpio_irq_handler(struct irq_desc *desc)
194
209
tqmx86_gpio_write (gpio , irq_status , TQMX86_GPIIS );
195
210
196
211
irq_bits = irq_status ;
212
+
213
+ raw_spin_lock_irqsave (& gpio -> spinlock , flags );
214
+ for_each_set_bit (i , & irq_bits , TQMX86_NGPI ) {
215
+ /*
216
+ * Edge-both triggers are implemented by flipping the edge
217
+ * trigger after each interrupt, as the controller only supports
218
+ * either rising or falling edge triggers, but not both.
219
+ *
220
+ * Internally, the TQMx86 GPIO controller has separate status
221
+ * registers for rising and falling edge interrupts. GPIIC
222
+ * configures which bits from which register are visible in the
223
+ * interrupt status register GPIIS and defines what triggers the
224
+ * parent IRQ line. Writing to GPIIS always clears both rising
225
+ * and falling interrupt flags internally, regardless of the
226
+ * currently configured trigger.
227
+ *
228
+ * In consequence, we can cleanly implement the edge-both
229
+ * trigger in software by first clearing the interrupt and then
230
+ * setting the new trigger based on the current GPIO input in
231
+ * tqmx86_gpio_irq_config() - even if an edge arrives between
232
+ * reading the input and setting the trigger, we will have a new
233
+ * interrupt pending.
234
+ */
235
+ if ((gpio -> irq_type [i ] & TQMX86_GPII_MASK ) == TQMX86_INT_BOTH )
236
+ tqmx86_gpio_irq_config (gpio , i );
237
+ }
238
+ raw_spin_unlock_irqrestore (& gpio -> spinlock , flags );
239
+
197
240
for_each_set_bit (i , & irq_bits , TQMX86_NGPI )
198
241
generic_handle_domain_irq (gpio -> chip .irq .domain ,
199
242
i + TQMX86_NGPO );
@@ -277,6 +320,13 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
277
320
278
321
tqmx86_gpio_write (gpio , (u8 )~TQMX86_DIR_INPUT_MASK , TQMX86_GPIODD );
279
322
323
+ /*
324
+ * Reading the previous output state is not possible with TQMx86 hardware.
325
+ * Initialize all outputs to 0 to have a defined state that matches the
326
+ * shadow register.
327
+ */
328
+ tqmx86_gpio_write (gpio , 0 , TQMX86_GPIOD );
329
+
280
330
chip = & gpio -> chip ;
281
331
chip -> label = "gpio-tqmx86" ;
282
332
chip -> owner = THIS_MODULE ;
0 commit comments