Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/i2c/busses/i2c-parport.c
15111 views
1
/* ------------------------------------------------------------------------ *
2
* i2c-parport.c I2C bus over parallel port *
3
* ------------------------------------------------------------------------ *
4
Copyright (C) 2003-2011 Jean Delvare <[email protected]>
5
6
Based on older i2c-philips-par.c driver
7
Copyright (C) 1995-2000 Simon G. Vogl
8
With some changes from:
9
Frodo Looijaard <[email protected]>
10
Kyösti Mälkki <[email protected]>
11
12
This program is free software; you can redistribute it and/or modify
13
it under the terms of the GNU General Public License as published by
14
the Free Software Foundation; either version 2 of the License, or
15
(at your option) any later version.
16
17
This program is distributed in the hope that it will be useful,
18
but WITHOUT ANY WARRANTY; without even the implied warranty of
19
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
GNU General Public License for more details.
21
22
You should have received a copy of the GNU General Public License
23
along with this program; if not, write to the Free Software
24
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
* ------------------------------------------------------------------------ */
26
27
#include <linux/kernel.h>
28
#include <linux/module.h>
29
#include <linux/init.h>
30
#include <linux/delay.h>
31
#include <linux/parport.h>
32
#include <linux/i2c.h>
33
#include <linux/i2c-algo-bit.h>
34
#include <linux/i2c-smbus.h>
35
#include <linux/slab.h>
36
#include <linux/list.h>
37
#include <linux/mutex.h>
38
#include "i2c-parport.h"
39
40
/* ----- Device list ------------------------------------------------------ */
41
42
struct i2c_par {
43
struct pardevice *pdev;
44
struct i2c_adapter adapter;
45
struct i2c_algo_bit_data algo_data;
46
struct i2c_smbus_alert_setup alert_data;
47
struct i2c_client *ara;
48
struct list_head node;
49
};
50
51
static LIST_HEAD(adapter_list);
52
static DEFINE_MUTEX(adapter_list_lock);
53
54
/* ----- Low-level parallel port access ----------------------------------- */
55
56
static void port_write_data(struct parport *p, unsigned char d)
57
{
58
parport_write_data(p, d);
59
}
60
61
static void port_write_control(struct parport *p, unsigned char d)
62
{
63
parport_write_control(p, d);
64
}
65
66
static unsigned char port_read_data(struct parport *p)
67
{
68
return parport_read_data(p);
69
}
70
71
static unsigned char port_read_status(struct parport *p)
72
{
73
return parport_read_status(p);
74
}
75
76
static unsigned char port_read_control(struct parport *p)
77
{
78
return parport_read_control(p);
79
}
80
81
static void (* const port_write[])(struct parport *, unsigned char) = {
82
port_write_data,
83
NULL,
84
port_write_control,
85
};
86
87
static unsigned char (* const port_read[])(struct parport *) = {
88
port_read_data,
89
port_read_status,
90
port_read_control,
91
};
92
93
/* ----- Unified line operation functions --------------------------------- */
94
95
static inline void line_set(struct parport *data, int state,
96
const struct lineop *op)
97
{
98
u8 oldval = port_read[op->port](data);
99
100
/* Touch only the bit(s) needed */
101
if ((op->inverted && !state) || (!op->inverted && state))
102
port_write[op->port](data, oldval | op->val);
103
else
104
port_write[op->port](data, oldval & ~op->val);
105
}
106
107
static inline int line_get(struct parport *data,
108
const struct lineop *op)
109
{
110
u8 oldval = port_read[op->port](data);
111
112
return ((op->inverted && (oldval & op->val) != op->val)
113
|| (!op->inverted && (oldval & op->val) == op->val));
114
}
115
116
/* ----- I2C algorithm call-back functions and structures ----------------- */
117
118
static void parport_setscl(void *data, int state)
119
{
120
line_set((struct parport *) data, state, &adapter_parm[type].setscl);
121
}
122
123
static void parport_setsda(void *data, int state)
124
{
125
line_set((struct parport *) data, state, &adapter_parm[type].setsda);
126
}
127
128
static int parport_getscl(void *data)
129
{
130
return line_get((struct parport *) data, &adapter_parm[type].getscl);
131
}
132
133
static int parport_getsda(void *data)
134
{
135
return line_get((struct parport *) data, &adapter_parm[type].getsda);
136
}
137
138
/* Encapsulate the functions above in the correct structure.
139
Note that this is only a template, from which the real structures are
140
copied. The attaching code will set getscl to NULL for adapters that
141
cannot read SCL back, and will also make the data field point to
142
the parallel port structure. */
143
static const struct i2c_algo_bit_data parport_algo_data = {
144
.setsda = parport_setsda,
145
.setscl = parport_setscl,
146
.getsda = parport_getsda,
147
.getscl = parport_getscl,
148
.udelay = 10, /* ~50 kbps */
149
.timeout = HZ,
150
};
151
152
/* ----- I2c and parallel port call-back functions and structures --------- */
153
154
void i2c_parport_irq(void *data)
155
{
156
struct i2c_par *adapter = data;
157
struct i2c_client *ara = adapter->ara;
158
159
if (ara) {
160
dev_dbg(&ara->dev, "SMBus alert received\n");
161
i2c_handle_smbus_alert(ara);
162
} else
163
dev_dbg(&adapter->adapter.dev,
164
"SMBus alert received but no ARA client!\n");
165
}
166
167
static void i2c_parport_attach(struct parport *port)
168
{
169
struct i2c_par *adapter;
170
171
adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
172
if (adapter == NULL) {
173
printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
174
return;
175
}
176
177
pr_debug("i2c-parport: attaching to %s\n", port->name);
178
parport_disable_irq(port);
179
adapter->pdev = parport_register_device(port, "i2c-parport",
180
NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
181
if (!adapter->pdev) {
182
printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
183
goto err_free;
184
}
185
186
/* Fill the rest of the structure */
187
adapter->adapter.owner = THIS_MODULE;
188
adapter->adapter.class = I2C_CLASS_HWMON;
189
strlcpy(adapter->adapter.name, "Parallel port adapter",
190
sizeof(adapter->adapter.name));
191
adapter->algo_data = parport_algo_data;
192
/* Slow down if we can't sense SCL */
193
if (!adapter_parm[type].getscl.val) {
194
adapter->algo_data.getscl = NULL;
195
adapter->algo_data.udelay = 50; /* ~10 kbps */
196
}
197
adapter->algo_data.data = port;
198
adapter->adapter.algo_data = &adapter->algo_data;
199
adapter->adapter.dev.parent = port->physport->dev;
200
201
if (parport_claim_or_block(adapter->pdev) < 0) {
202
printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
203
goto err_unregister;
204
}
205
206
/* Reset hardware to a sane state (SCL and SDA high) */
207
parport_setsda(port, 1);
208
parport_setscl(port, 1);
209
/* Other init if needed (power on...) */
210
if (adapter_parm[type].init.val) {
211
line_set(port, 1, &adapter_parm[type].init);
212
/* Give powered devices some time to settle */
213
msleep(100);
214
}
215
216
if (i2c_bit_add_bus(&adapter->adapter) < 0) {
217
printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
218
goto err_unregister;
219
}
220
221
/* Setup SMBus alert if supported */
222
if (adapter_parm[type].smbus_alert) {
223
adapter->alert_data.alert_edge_triggered = 1;
224
adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
225
&adapter->alert_data);
226
if (adapter->ara)
227
parport_enable_irq(port);
228
else
229
printk(KERN_WARNING "i2c-parport: Failed to register "
230
"ARA client\n");
231
}
232
233
/* Add the new adapter to the list */
234
mutex_lock(&adapter_list_lock);
235
list_add_tail(&adapter->node, &adapter_list);
236
mutex_unlock(&adapter_list_lock);
237
return;
238
239
err_unregister:
240
parport_release(adapter->pdev);
241
parport_unregister_device(adapter->pdev);
242
err_free:
243
kfree(adapter);
244
}
245
246
static void i2c_parport_detach(struct parport *port)
247
{
248
struct i2c_par *adapter, *_n;
249
250
/* Walk the list */
251
mutex_lock(&adapter_list_lock);
252
list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
253
if (adapter->pdev->port == port) {
254
if (adapter->ara) {
255
parport_disable_irq(port);
256
i2c_unregister_device(adapter->ara);
257
}
258
i2c_del_adapter(&adapter->adapter);
259
260
/* Un-init if needed (power off...) */
261
if (adapter_parm[type].init.val)
262
line_set(port, 0, &adapter_parm[type].init);
263
264
parport_release(adapter->pdev);
265
parport_unregister_device(adapter->pdev);
266
list_del(&adapter->node);
267
kfree(adapter);
268
}
269
}
270
mutex_unlock(&adapter_list_lock);
271
}
272
273
static struct parport_driver i2c_parport_driver = {
274
.name = "i2c-parport",
275
.attach = i2c_parport_attach,
276
.detach = i2c_parport_detach,
277
};
278
279
/* ----- Module loading, unloading and information ------------------------ */
280
281
static int __init i2c_parport_init(void)
282
{
283
if (type < 0) {
284
printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
285
return -ENODEV;
286
}
287
288
if (type >= ARRAY_SIZE(adapter_parm)) {
289
printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
290
return -ENODEV;
291
}
292
293
return parport_register_driver(&i2c_parport_driver);
294
}
295
296
static void __exit i2c_parport_exit(void)
297
{
298
parport_unregister_driver(&i2c_parport_driver);
299
}
300
301
MODULE_AUTHOR("Jean Delvare <[email protected]>");
302
MODULE_DESCRIPTION("I2C bus over parallel port");
303
MODULE_LICENSE("GPL");
304
305
module_init(i2c_parport_init);
306
module_exit(i2c_parport_exit);
307
308