1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 SiFive
*/
#include <linux/basic_mmio_gpio.h>
#include <printk.h>
#include <driver.h>
#include <errno.h>
#define SIFIVE_GPIO_INPUT_VAL 0x00
#define SIFIVE_GPIO_INPUT_EN 0x04
#define SIFIVE_GPIO_OUTPUT_EN 0x08
#define SIFIVE_GPIO_OUTPUT_VAL 0x0C
#define SIFIVE_GPIO_RISE_IE 0x18
#define SIFIVE_GPIO_FALL_IE 0x20
#define SIFIVE_GPIO_HIGH_IE 0x28
#define SIFIVE_GPIO_LOW_IE 0x30
#define SIFIVE_GPIO_MAX 32
static int __of_irq_count(struct device_node *np)
{
unsigned npins = 0;
of_get_property(np, "interrupts", &npins);
return npins / sizeof(__be32);
}
static int sifive_gpio_probe(struct device_d *dev)
{
struct bgpio_chip *bgc;
struct resource *res;
void __iomem *base;
int ret, ngpio;
bgc = xzalloc(sizeof(*bgc));
res = dev_request_mem_resource(dev, 0);
if (IS_ERR(res)) {
dev_err(dev, "failed to request device memory\n");
return PTR_ERR(res);
}
base = IOMEM(res->start);
ngpio = __of_irq_count(dev->device_node);
if (ngpio > SIFIVE_GPIO_MAX) {
dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
SIFIVE_GPIO_MAX);
return -ENXIO;
}
ret = bgpio_init(bgc, dev, 4,
base + SIFIVE_GPIO_INPUT_VAL,
base + SIFIVE_GPIO_OUTPUT_VAL,
NULL,
base + SIFIVE_GPIO_OUTPUT_EN,
base + SIFIVE_GPIO_INPUT_EN,
0);
if (ret) {
dev_err(dev, "unable to init generic GPIO\n");
return ret;
}
/* Disable all GPIO interrupts */
writel(0, base + SIFIVE_GPIO_RISE_IE);
writel(0, base + SIFIVE_GPIO_FALL_IE);
writel(0, base + SIFIVE_GPIO_HIGH_IE);
writel(0, base + SIFIVE_GPIO_LOW_IE);
bgc->gc.ngpio = ngpio;
return gpiochip_add(&bgc->gc);
}
static const struct of_device_id sifive_gpio_match[] = {
{ .compatible = "sifive,gpio0" },
{ .compatible = "sifive,fu540-c000-gpio" },
{ },
};
static struct driver_d sifive_gpio_driver = {
.name = "sifive_gpio",
.of_compatible = sifive_gpio_match,
.probe = sifive_gpio_probe,
};
postcore_platform_driver(sifive_gpio_driver);
|