]>
Commit | Line | Data |
---|---|---|
bf3a00f8 | 1 | /* |
0f13804a | 2 | * Interrupt handling for IPR-based IRQ. |
1da177e4 LT |
3 | * |
4 | * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi | |
5 | * Copyright (C) 2000 Kazumoto Kojima | |
0f13804a PM |
6 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> |
7 | * Copyright (C) 2006 Paul Mundt | |
1da177e4 LT |
8 | * |
9 | * Supported system: | |
10 | * On-chip supporting modules (TMU, RTC, etc.). | |
d89ddd1c | 11 | * On-chip supporting modules for SH7709/SH7709A/SH7729. |
1da177e4 LT |
12 | * Hitachi SolutionEngine external I/O: |
13 | * MS7709SE01, MS7709ASE01, and MS7750SE01 | |
14 | * | |
0f13804a PM |
15 | * This file is subject to the terms and conditions of the GNU General Public |
16 | * License. See the file "COPYING" in the main directory of this archive | |
17 | * for more details. | |
1da177e4 | 18 | */ |
1da177e4 | 19 | #include <linux/init.h> |
f701b399 NP |
20 | #include <linux/interrupt.h> |
21 | #include <linux/io.h> | |
1da177e4 | 22 | #include <linux/irq.h> |
f701b399 | 23 | #include <linux/kernel.h> |
1da177e4 | 24 | #include <linux/module.h> |
54ff328b | 25 | #include <linux/topology.h> |
1da177e4 | 26 | |
8df3a615 | 27 | static inline struct ipr_desc *get_ipr_desc(struct irq_data *data) |
68abdbbb | 28 | { |
8df3a615 | 29 | struct irq_chip *chip = irq_data_get_irq_chip(data); |
f701b399 | 30 | return container_of(chip, struct ipr_desc, chip); |
68abdbbb MD |
31 | } |
32 | ||
8df3a615 | 33 | static void disable_ipr_irq(struct irq_data *data) |
1da177e4 | 34 | { |
8df3a615 PM |
35 | struct ipr_data *p = irq_data_get_irq_chip_data(data); |
36 | unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx]; | |
1da177e4 | 37 | /* Set the priority in IPR to 0 */ |
62429e03 | 38 | __raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr); |
6000fc4d | 39 | (void)__raw_readw(addr); /* Read back to flush write posting */ |
1da177e4 LT |
40 | } |
41 | ||
8df3a615 | 42 | static void enable_ipr_irq(struct irq_data *data) |
1da177e4 | 43 | { |
8df3a615 PM |
44 | struct ipr_data *p = irq_data_get_irq_chip_data(data); |
45 | unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx]; | |
1da177e4 | 46 | /* Set priority in IPR back to original value */ |
62429e03 | 47 | __raw_writew(__raw_readw(addr) | (p->priority << p->shift), addr); |
1da177e4 LT |
48 | } |
49 | ||
68abdbbb MD |
50 | /* |
51 | * The shift value is now the number of bits to shift, not the number of | |
52 | * bits/4. This is to make it easier to read the value directly from the | |
53 | * datasheets. The IPR address is calculated using the ipr_offset table. | |
54 | */ | |
68abdbbb | 55 | void register_ipr_controller(struct ipr_desc *desc) |
1da177e4 | 56 | { |
bd71ab88 | 57 | int i; |
0f13804a | 58 | |
8df3a615 PM |
59 | desc->chip.irq_mask = disable_ipr_irq; |
60 | desc->chip.irq_unmask = enable_ipr_irq; | |
f725b5ee | 61 | |
68abdbbb MD |
62 | for (i = 0; i < desc->nr_irqs; i++) { |
63 | struct ipr_data *p = desc->ipr_data + i; | |
c4318baf | 64 | int res; |
f725b5ee | 65 | |
68abdbbb MD |
66 | BUG_ON(p->ipr_idx >= desc->nr_offsets); |
67 | BUG_ON(!desc->ipr_offsets[p->ipr_idx]); | |
f725b5ee | 68 | |
c4318baf | 69 | res = irq_alloc_desc_at(p->irq, numa_node_id()); |
8df3a615 | 70 | if (unlikely(res != p->irq && res != -EEXIST)) { |
05ff3004 PM |
71 | printk(KERN_INFO "can not get irq_desc for %d\n", |
72 | p->irq); | |
73 | continue; | |
74 | } | |
75 | ||
68abdbbb MD |
76 | disable_irq_nosync(p->irq); |
77 | set_irq_chip_and_handler_name(p->irq, &desc->chip, | |
709bc44c | 78 | handle_level_irq, "level"); |
68abdbbb | 79 | set_irq_chip_data(p->irq, p); |
8df3a615 | 80 | disable_ipr_irq(irq_get_irq_data(p->irq)); |
bd71ab88 | 81 | } |
1da177e4 | 82 | } |
68abdbbb | 83 | EXPORT_SYMBOL(register_ipr_controller); |