Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpio/gpio-en7523.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
3
#include <linux/types.h>
4
#include <linux/io.h>
5
#include <linux/bits.h>
6
#include <linux/gpio/driver.h>
7
#include <linux/gpio/generic.h>
8
#include <linux/mod_devicetable.h>
9
#include <linux/module.h>
10
#include <linux/platform_device.h>
11
#include <linux/property.h>
12
13
#define AIROHA_GPIO_MAX 32
14
15
/**
16
* struct airoha_gpio_ctrl - Airoha GPIO driver data
17
* @gen_gc: Associated gpio_generic_chip instance.
18
* @data: The data register.
19
* @dir: [0] The direction register for the lower 16 pins.
20
* [1]: The direction register for the higher 16 pins.
21
* @output: The output enable register.
22
*/
23
struct airoha_gpio_ctrl {
24
struct gpio_generic_chip gen_gc;
25
void __iomem *data;
26
void __iomem *dir[2];
27
void __iomem *output;
28
};
29
30
static int airoha_dir_set(struct gpio_chip *gc, unsigned int gpio,
31
int val, int out)
32
{
33
struct airoha_gpio_ctrl *ctrl = gpiochip_get_data(gc);
34
u32 dir = ioread32(ctrl->dir[gpio / 16]);
35
u32 output = ioread32(ctrl->output);
36
u32 mask = BIT((gpio % 16) * 2);
37
38
if (out) {
39
dir |= mask;
40
output |= BIT(gpio);
41
} else {
42
dir &= ~mask;
43
output &= ~BIT(gpio);
44
}
45
46
iowrite32(dir, ctrl->dir[gpio / 16]);
47
48
if (out)
49
gpio_generic_chip_set(&ctrl->gen_gc, gpio, val);
50
51
iowrite32(output, ctrl->output);
52
53
return 0;
54
}
55
56
static int airoha_dir_out(struct gpio_chip *gc, unsigned int gpio,
57
int val)
58
{
59
return airoha_dir_set(gc, gpio, val, 1);
60
}
61
62
static int airoha_dir_in(struct gpio_chip *gc, unsigned int gpio)
63
{
64
return airoha_dir_set(gc, gpio, 0, 0);
65
}
66
67
static int airoha_get_dir(struct gpio_chip *gc, unsigned int gpio)
68
{
69
struct airoha_gpio_ctrl *ctrl = gpiochip_get_data(gc);
70
u32 dir = ioread32(ctrl->dir[gpio / 16]);
71
u32 mask = BIT((gpio % 16) * 2);
72
73
return (dir & mask) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
74
}
75
76
static int airoha_gpio_probe(struct platform_device *pdev)
77
{
78
struct gpio_generic_chip_config config = { };
79
struct device *dev = &pdev->dev;
80
struct airoha_gpio_ctrl *ctrl;
81
int err;
82
83
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
84
if (!ctrl)
85
return -ENOMEM;
86
87
ctrl->data = devm_platform_ioremap_resource(pdev, 0);
88
if (IS_ERR(ctrl->data))
89
return PTR_ERR(ctrl->data);
90
91
ctrl->dir[0] = devm_platform_ioremap_resource(pdev, 1);
92
if (IS_ERR(ctrl->dir[0]))
93
return PTR_ERR(ctrl->dir[0]);
94
95
ctrl->dir[1] = devm_platform_ioremap_resource(pdev, 2);
96
if (IS_ERR(ctrl->dir[1]))
97
return PTR_ERR(ctrl->dir[1]);
98
99
ctrl->output = devm_platform_ioremap_resource(pdev, 3);
100
if (IS_ERR(ctrl->output))
101
return PTR_ERR(ctrl->output);
102
103
config.dev = dev;
104
config.sz = 4;
105
config.dat = ctrl->data;
106
107
err = gpio_generic_chip_init(&ctrl->gen_gc, &config);
108
if (err)
109
return dev_err_probe(dev, err, "unable to init generic GPIO");
110
111
ctrl->gen_gc.gc.ngpio = AIROHA_GPIO_MAX;
112
ctrl->gen_gc.gc.owner = THIS_MODULE;
113
ctrl->gen_gc.gc.direction_output = airoha_dir_out;
114
ctrl->gen_gc.gc.direction_input = airoha_dir_in;
115
ctrl->gen_gc.gc.get_direction = airoha_get_dir;
116
117
return devm_gpiochip_add_data(dev, &ctrl->gen_gc.gc, ctrl);
118
}
119
120
static const struct of_device_id airoha_gpio_of_match[] = {
121
{ .compatible = "airoha,en7523-gpio" },
122
{ }
123
};
124
MODULE_DEVICE_TABLE(of, airoha_gpio_of_match);
125
126
static struct platform_driver airoha_gpio_driver = {
127
.driver = {
128
.name = "airoha-gpio",
129
.of_match_table = airoha_gpio_of_match,
130
},
131
.probe = airoha_gpio_probe,
132
};
133
module_platform_driver(airoha_gpio_driver);
134
135
MODULE_DESCRIPTION("Airoha GPIO support");
136
MODULE_AUTHOR("John Crispin <[email protected]>");
137
MODULE_LICENSE("GPL v2");
138
139