Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/gpio/janz-ttl.c
15109 views
1
/*
2
* Janz MODULbus VMOD-TTL GPIO Driver
3
*
4
* Copyright (c) 2010 Ira W. Snyder <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the
8
* Free Software Foundation; either version 2 of the License, or (at your
9
* option) any later version.
10
*/
11
12
#include <linux/kernel.h>
13
#include <linux/module.h>
14
#include <linux/init.h>
15
#include <linux/interrupt.h>
16
#include <linux/delay.h>
17
#include <linux/platform_device.h>
18
#include <linux/io.h>
19
#include <linux/gpio.h>
20
#include <linux/slab.h>
21
22
#include <linux/mfd/janz.h>
23
24
#define DRV_NAME "janz-ttl"
25
26
#define PORTA_DIRECTION 0x23
27
#define PORTB_DIRECTION 0x2B
28
#define PORTC_DIRECTION 0x06
29
#define PORTA_IOCTL 0x24
30
#define PORTB_IOCTL 0x2C
31
#define PORTC_IOCTL 0x07
32
33
#define MASTER_INT_CTL 0x00
34
#define MASTER_CONF_CTL 0x01
35
36
#define CONF_PAE (1 << 2)
37
#define CONF_PBE (1 << 7)
38
#define CONF_PCE (1 << 4)
39
40
struct ttl_control_regs {
41
__be16 portc;
42
__be16 portb;
43
__be16 porta;
44
__be16 control;
45
};
46
47
struct ttl_module {
48
struct gpio_chip gpio;
49
50
/* base address of registers */
51
struct ttl_control_regs __iomem *regs;
52
53
u8 portc_shadow;
54
u8 portb_shadow;
55
u8 porta_shadow;
56
57
spinlock_t lock;
58
};
59
60
static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
61
{
62
struct ttl_module *mod = dev_get_drvdata(gpio->dev);
63
u8 *shadow;
64
int ret;
65
66
if (offset < 8) {
67
shadow = &mod->porta_shadow;
68
} else if (offset < 16) {
69
shadow = &mod->portb_shadow;
70
offset -= 8;
71
} else {
72
shadow = &mod->portc_shadow;
73
offset -= 16;
74
}
75
76
spin_lock(&mod->lock);
77
ret = *shadow & (1 << offset);
78
spin_unlock(&mod->lock);
79
return ret;
80
}
81
82
static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
83
{
84
struct ttl_module *mod = dev_get_drvdata(gpio->dev);
85
void __iomem *port;
86
u8 *shadow;
87
88
if (offset < 8) {
89
port = &mod->regs->porta;
90
shadow = &mod->porta_shadow;
91
} else if (offset < 16) {
92
port = &mod->regs->portb;
93
shadow = &mod->portb_shadow;
94
offset -= 8;
95
} else {
96
port = &mod->regs->portc;
97
shadow = &mod->portc_shadow;
98
offset -= 16;
99
}
100
101
spin_lock(&mod->lock);
102
if (value)
103
*shadow |= (1 << offset);
104
else
105
*shadow &= ~(1 << offset);
106
107
iowrite16be(*shadow, port);
108
spin_unlock(&mod->lock);
109
}
110
111
static void __devinit ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
112
{
113
iowrite16be(reg, &mod->regs->control);
114
iowrite16be(val, &mod->regs->control);
115
}
116
117
static void __devinit ttl_setup_device(struct ttl_module *mod)
118
{
119
/* reset the device to a known state */
120
iowrite16be(0x0000, &mod->regs->control);
121
iowrite16be(0x0001, &mod->regs->control);
122
iowrite16be(0x0000, &mod->regs->control);
123
124
/* put all ports in open-drain mode */
125
ttl_write_reg(mod, PORTA_IOCTL, 0x00ff);
126
ttl_write_reg(mod, PORTB_IOCTL, 0x00ff);
127
ttl_write_reg(mod, PORTC_IOCTL, 0x000f);
128
129
/* set all ports as outputs */
130
ttl_write_reg(mod, PORTA_DIRECTION, 0x0000);
131
ttl_write_reg(mod, PORTB_DIRECTION, 0x0000);
132
ttl_write_reg(mod, PORTC_DIRECTION, 0x0000);
133
134
/* set all ports to drive zeroes */
135
iowrite16be(0x0000, &mod->regs->porta);
136
iowrite16be(0x0000, &mod->regs->portb);
137
iowrite16be(0x0000, &mod->regs->portc);
138
139
/* enable all ports */
140
ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE);
141
}
142
143
static int __devinit ttl_probe(struct platform_device *pdev)
144
{
145
struct janz_platform_data *pdata;
146
struct device *dev = &pdev->dev;
147
struct ttl_module *mod;
148
struct gpio_chip *gpio;
149
struct resource *res;
150
int ret;
151
152
pdata = pdev->dev.platform_data;
153
if (!pdata) {
154
dev_err(dev, "no platform data\n");
155
ret = -ENXIO;
156
goto out_return;
157
}
158
159
mod = kzalloc(sizeof(*mod), GFP_KERNEL);
160
if (!mod) {
161
dev_err(dev, "unable to allocate private data\n");
162
ret = -ENOMEM;
163
goto out_return;
164
}
165
166
platform_set_drvdata(pdev, mod);
167
spin_lock_init(&mod->lock);
168
169
/* get access to the MODULbus registers for this module */
170
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
171
if (!res) {
172
dev_err(dev, "MODULbus registers not found\n");
173
ret = -ENODEV;
174
goto out_free_mod;
175
}
176
177
mod->regs = ioremap(res->start, resource_size(res));
178
if (!mod->regs) {
179
dev_err(dev, "MODULbus registers not ioremap\n");
180
ret = -ENOMEM;
181
goto out_free_mod;
182
}
183
184
ttl_setup_device(mod);
185
186
/* Initialize the GPIO data structures */
187
gpio = &mod->gpio;
188
gpio->dev = &pdev->dev;
189
gpio->label = pdev->name;
190
gpio->get = ttl_get_value;
191
gpio->set = ttl_set_value;
192
gpio->owner = THIS_MODULE;
193
194
/* request dynamic allocation */
195
gpio->base = -1;
196
gpio->ngpio = 20;
197
198
ret = gpiochip_add(gpio);
199
if (ret) {
200
dev_err(dev, "unable to add GPIO chip\n");
201
goto out_iounmap_regs;
202
}
203
204
dev_info(&pdev->dev, "module %d: registered GPIO device\n",
205
pdata->modno);
206
return 0;
207
208
out_iounmap_regs:
209
iounmap(mod->regs);
210
out_free_mod:
211
kfree(mod);
212
out_return:
213
return ret;
214
}
215
216
static int __devexit ttl_remove(struct platform_device *pdev)
217
{
218
struct ttl_module *mod = platform_get_drvdata(pdev);
219
struct device *dev = &pdev->dev;
220
int ret;
221
222
ret = gpiochip_remove(&mod->gpio);
223
if (ret) {
224
dev_err(dev, "unable to remove GPIO chip\n");
225
return ret;
226
}
227
228
iounmap(mod->regs);
229
kfree(mod);
230
return 0;
231
}
232
233
static struct platform_driver ttl_driver = {
234
.driver = {
235
.name = DRV_NAME,
236
.owner = THIS_MODULE,
237
},
238
.probe = ttl_probe,
239
.remove = __devexit_p(ttl_remove),
240
};
241
242
static int __init ttl_init(void)
243
{
244
return platform_driver_register(&ttl_driver);
245
}
246
247
static void __exit ttl_exit(void)
248
{
249
platform_driver_unregister(&ttl_driver);
250
}
251
252
MODULE_AUTHOR("Ira W. Snyder <[email protected]>");
253
MODULE_DESCRIPTION("Janz MODULbus VMOD-TTL Driver");
254
MODULE_LICENSE("GPL");
255
MODULE_ALIAS("platform:janz-ttl");
256
257
module_init(ttl_init);
258
module_exit(ttl_exit);
259
260