Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/boards/mach-x3proto/gpio.c
15126 views
1
/*
2
* arch/sh/boards/mach-x3proto/gpio.c
3
*
4
* Renesas SH-X3 Prototype Baseboard GPIO Support.
5
*
6
* Copyright (C) 2010 Paul Mundt
7
*
8
* This file is subject to the terms and conditions of the GNU General Public
9
* License. See the file "COPYING" in the main directory of this archive
10
* for more details.
11
*/
12
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14
#include <linux/init.h>
15
#include <linux/interrupt.h>
16
#include <linux/gpio.h>
17
#include <linux/irq.h>
18
#include <linux/kernel.h>
19
#include <linux/spinlock.h>
20
#include <linux/io.h>
21
#include <mach/ilsel.h>
22
#include <mach/hardware.h>
23
24
#define KEYCTLR 0xb81c0000
25
#define KEYOUTR 0xb81c0002
26
#define KEYDETR 0xb81c0004
27
28
static DEFINE_SPINLOCK(x3proto_gpio_lock);
29
static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
30
31
static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
32
{
33
unsigned long flags;
34
unsigned int data;
35
36
spin_lock_irqsave(&x3proto_gpio_lock, flags);
37
data = __raw_readw(KEYCTLR);
38
data |= (1 << gpio);
39
__raw_writew(data, KEYCTLR);
40
spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
41
42
return 0;
43
}
44
45
static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
46
{
47
return !!(__raw_readw(KEYDETR) & (1 << gpio));
48
}
49
50
static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
51
{
52
return x3proto_gpio_irq_map[gpio];
53
}
54
55
static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
56
{
57
struct irq_data *data = irq_get_irq_data(irq);
58
struct irq_chip *chip = irq_data_get_irq_chip(data);
59
unsigned long mask;
60
int pin;
61
62
chip->irq_mask_ack(data);
63
64
mask = __raw_readw(KEYDETR);
65
66
for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
67
generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
68
69
chip->irq_unmask(data);
70
}
71
72
struct gpio_chip x3proto_gpio_chip = {
73
.label = "x3proto-gpio",
74
.direction_input = x3proto_gpio_direction_input,
75
.get = x3proto_gpio_get,
76
.to_irq = x3proto_gpio_to_irq,
77
.base = -1,
78
.ngpio = NR_BASEBOARD_GPIOS,
79
};
80
81
int __init x3proto_gpio_setup(void)
82
{
83
int ilsel;
84
int ret, i;
85
86
ilsel = ilsel_enable(ILSEL_KEY);
87
if (unlikely(ilsel < 0))
88
return ilsel;
89
90
ret = gpiochip_add(&x3proto_gpio_chip);
91
if (unlikely(ret))
92
goto err_gpio;
93
94
for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
95
unsigned long flags;
96
int irq = create_irq();
97
98
if (unlikely(irq < 0)) {
99
ret = -EINVAL;
100
goto err_irq;
101
}
102
103
spin_lock_irqsave(&x3proto_gpio_lock, flags);
104
x3proto_gpio_irq_map[i] = irq;
105
irq_set_chip_and_handler_name(irq, &dummy_irq_chip,
106
handle_simple_irq, "gpio");
107
spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
108
}
109
110
pr_info("registering '%s' support, handling GPIOs %u -> %u, "
111
"bound to IRQ %u\n",
112
x3proto_gpio_chip.label, x3proto_gpio_chip.base,
113
x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
114
ilsel);
115
116
irq_set_chained_handler(ilsel, x3proto_gpio_irq_handler);
117
irq_set_irq_wake(ilsel, 1);
118
119
return 0;
120
121
err_irq:
122
for (; i >= 0; --i)
123
if (x3proto_gpio_irq_map[i])
124
destroy_irq(x3proto_gpio_irq_map[i]);
125
126
ret = gpiochip_remove(&x3proto_gpio_chip);
127
if (unlikely(ret))
128
pr_err("Failed deregistering GPIO\n");
129
130
err_gpio:
131
synchronize_irq(ilsel);
132
133
ilsel_disable(ILSEL_KEY);
134
135
return ret;
136
}
137
138