1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* ------------------------------------------------------------------------ * |
3 | * i2c-parport.c I2C bus over parallel port * |
4 | * ------------------------------------------------------------------------ * |
5 | Copyright (C) 2003-2011 Jean Delvare <jdelvare@suse.de> |
6 | |
7 | Based on older i2c-philips-par.c driver |
8 | Copyright (C) 1995-2000 Simon G. Vogl |
9 | With some changes from: |
10 | Frodo Looijaard <frodol@dds.nl> |
11 | Kyösti Mälkki <kmalkki@cc.hut.fi> |
12 | |
13 | * ------------------------------------------------------------------------ */ |
14 | |
15 | #define pr_fmt(fmt) "i2c-parport: " fmt |
16 | |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> |
19 | #include <linux/init.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/parport.h> |
22 | #include <linux/i2c.h> |
23 | #include <linux/i2c-algo-bit.h> |
24 | #include <linux/i2c-smbus.h> |
25 | #include <linux/slab.h> |
26 | #include <linux/list.h> |
27 | #include <linux/mutex.h> |
28 | |
29 | #define PORT_DATA 0 |
30 | #define PORT_STAT 1 |
31 | #define PORT_CTRL 2 |
32 | |
33 | struct lineop { |
34 | u8 val; |
35 | u8 port; |
36 | u8 inverted; |
37 | }; |
38 | |
39 | struct adapter_parm { |
40 | struct lineop setsda; |
41 | struct lineop setscl; |
42 | struct lineop getsda; |
43 | struct lineop getscl; |
44 | struct lineop init; |
45 | unsigned int smbus_alert:1; |
46 | }; |
47 | |
48 | static const struct adapter_parm adapter_parm[] = { |
49 | /* type 0: Philips adapter */ |
50 | { |
51 | .setsda = { .val: 0x80, PORT_DATA, .inverted: 1 }, |
52 | .setscl = { 0x08, PORT_CTRL, 0 }, |
53 | .getsda = { 0x80, PORT_STAT, 0 }, |
54 | .getscl = { 0x08, PORT_STAT, 0 }, |
55 | }, |
56 | /* type 1: home brew teletext adapter */ |
57 | { |
58 | .setsda = { 0x02, PORT_DATA, 0 }, |
59 | .setscl = { 0x01, PORT_DATA, 0 }, |
60 | .getsda = { 0x80, PORT_STAT, 1 }, |
61 | }, |
62 | /* type 2: Velleman K8000 adapter */ |
63 | { |
64 | .setsda = { 0x02, PORT_CTRL, 1 }, |
65 | .setscl = { 0x08, PORT_CTRL, 1 }, |
66 | .getsda = { 0x10, PORT_STAT, 0 }, |
67 | }, |
68 | /* type 3: ELV adapter */ |
69 | { |
70 | .setsda = { 0x02, PORT_DATA, 1 }, |
71 | .setscl = { 0x01, PORT_DATA, 1 }, |
72 | .getsda = { 0x40, PORT_STAT, 1 }, |
73 | .getscl = { 0x08, PORT_STAT, 1 }, |
74 | }, |
75 | /* type 4: ADM1032 evaluation board */ |
76 | { |
77 | .setsda = { 0x02, PORT_DATA, 1 }, |
78 | .setscl = { 0x01, PORT_DATA, 1 }, |
79 | .getsda = { 0x10, PORT_STAT, 1 }, |
80 | .init = { 0xf0, PORT_DATA, 0 }, |
81 | .smbus_alert = 1, |
82 | }, |
83 | /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */ |
84 | { |
85 | .setsda = { 0x02, PORT_DATA, 1 }, |
86 | .setscl = { 0x01, PORT_DATA, 1 }, |
87 | .getsda = { 0x10, PORT_STAT, 1 }, |
88 | }, |
89 | /* type 6: Barco LPT->DVI (K5800236) adapter */ |
90 | { |
91 | .setsda = { 0x02, PORT_DATA, 1 }, |
92 | .setscl = { 0x01, PORT_DATA, 1 }, |
93 | .getsda = { 0x20, PORT_STAT, 0 }, |
94 | .getscl = { 0x40, PORT_STAT, 0 }, |
95 | .init = { 0xfc, PORT_DATA, 0 }, |
96 | }, |
97 | /* type 7: One For All JP1 parallel port adapter */ |
98 | { |
99 | .setsda = { 0x01, PORT_DATA, 0 }, |
100 | .setscl = { 0x02, PORT_DATA, 0 }, |
101 | .getsda = { 0x80, PORT_STAT, 1 }, |
102 | .init = { 0x04, PORT_DATA, 1 }, |
103 | }, |
104 | /* type 8: VCT-jig */ |
105 | { |
106 | .setsda = { 0x04, PORT_DATA, 1 }, |
107 | .setscl = { 0x01, PORT_DATA, 1 }, |
108 | .getsda = { 0x40, PORT_STAT, 0 }, |
109 | .getscl = { 0x80, PORT_STAT, 1 }, |
110 | }, |
111 | }; |
112 | |
113 | /* ----- Device list ------------------------------------------------------ */ |
114 | |
115 | struct i2c_par { |
116 | struct pardevice *pdev; |
117 | struct i2c_adapter adapter; |
118 | struct i2c_algo_bit_data algo_data; |
119 | struct i2c_smbus_alert_setup alert_data; |
120 | struct i2c_client *ara; |
121 | struct list_head node; |
122 | }; |
123 | |
124 | static LIST_HEAD(adapter_list); |
125 | static DEFINE_MUTEX(adapter_list_lock); |
126 | |
127 | #define MAX_DEVICE 4 |
128 | static int parport[MAX_DEVICE] = {0, -1, -1, -1}; |
129 | module_param_array(parport, int, NULL, 0); |
130 | MODULE_PARM_DESC(parport, |
131 | "List of parallel ports to bind to, by index.\n" |
132 | " At most " __stringify(MAX_DEVICE) " devices are supported.\n" |
133 | " Default is one device connected to parport0.\n" |
134 | ); |
135 | |
136 | static int type = -1; |
137 | module_param(type, int, 0); |
138 | MODULE_PARM_DESC(type, |
139 | "Type of adapter:\n" |
140 | " 0 = Philips adapter\n" |
141 | " 1 = home brew teletext adapter\n" |
142 | " 2 = Velleman K8000 adapter\n" |
143 | " 3 = ELV adapter\n" |
144 | " 4 = ADM1032 evaluation board\n" |
145 | " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n" |
146 | " 6 = Barco LPT->DVI (K5800236) adapter\n" |
147 | " 7 = One For All JP1 parallel port adapter\n" |
148 | " 8 = VCT-jig\n" |
149 | ); |
150 | |
151 | /* ----- Low-level parallel port access ----------------------------------- */ |
152 | |
153 | static void port_write_data(struct parport *p, unsigned char d) |
154 | { |
155 | parport_write_data(p, d); |
156 | } |
157 | |
158 | static void port_write_control(struct parport *p, unsigned char d) |
159 | { |
160 | parport_write_control(p, d); |
161 | } |
162 | |
163 | static unsigned char port_read_data(struct parport *p) |
164 | { |
165 | return parport_read_data(p); |
166 | } |
167 | |
168 | static unsigned char port_read_status(struct parport *p) |
169 | { |
170 | return parport_read_status(p); |
171 | } |
172 | |
173 | static unsigned char port_read_control(struct parport *p) |
174 | { |
175 | return parport_read_control(p); |
176 | } |
177 | |
178 | static void (* const port_write[])(struct parport *, unsigned char) = { |
179 | port_write_data, |
180 | NULL, |
181 | port_write_control, |
182 | }; |
183 | |
184 | static unsigned char (* const port_read[])(struct parport *) = { |
185 | port_read_data, |
186 | port_read_status, |
187 | port_read_control, |
188 | }; |
189 | |
190 | /* ----- Unified line operation functions --------------------------------- */ |
191 | |
192 | static inline void line_set(struct parport *data, int state, |
193 | const struct lineop *op) |
194 | { |
195 | u8 oldval = port_read[op->port](data); |
196 | |
197 | /* Touch only the bit(s) needed */ |
198 | if ((op->inverted && !state) || (!op->inverted && state)) |
199 | port_write[op->port](data, oldval | op->val); |
200 | else |
201 | port_write[op->port](data, oldval & ~op->val); |
202 | } |
203 | |
204 | static inline int line_get(struct parport *data, |
205 | const struct lineop *op) |
206 | { |
207 | u8 oldval = port_read[op->port](data); |
208 | |
209 | return ((op->inverted && (oldval & op->val) != op->val) |
210 | || (!op->inverted && (oldval & op->val) == op->val)); |
211 | } |
212 | |
213 | /* ----- I2C algorithm call-back functions and structures ----------------- */ |
214 | |
215 | static void parport_setscl(void *data, int state) |
216 | { |
217 | line_set(data: (struct parport *) data, state, op: &adapter_parm[type].setscl); |
218 | } |
219 | |
220 | static void parport_setsda(void *data, int state) |
221 | { |
222 | line_set(data: (struct parport *) data, state, op: &adapter_parm[type].setsda); |
223 | } |
224 | |
225 | static int parport_getscl(void *data) |
226 | { |
227 | return line_get(data: (struct parport *) data, op: &adapter_parm[type].getscl); |
228 | } |
229 | |
230 | static int parport_getsda(void *data) |
231 | { |
232 | return line_get(data: (struct parport *) data, op: &adapter_parm[type].getsda); |
233 | } |
234 | |
235 | /* Encapsulate the functions above in the correct structure. |
236 | Note that this is only a template, from which the real structures are |
237 | copied. The attaching code will set getscl to NULL for adapters that |
238 | cannot read SCL back, and will also make the data field point to |
239 | the parallel port structure. */ |
240 | static const struct i2c_algo_bit_data parport_algo_data = { |
241 | .setsda = parport_setsda, |
242 | .setscl = parport_setscl, |
243 | .getsda = parport_getsda, |
244 | .getscl = parport_getscl, |
245 | .udelay = 10, /* ~50 kbps */ |
246 | .timeout = HZ, |
247 | }; |
248 | |
249 | /* ----- I2c and parallel port call-back functions and structures --------- */ |
250 | |
251 | static void i2c_parport_irq(void *data) |
252 | { |
253 | struct i2c_par *adapter = data; |
254 | struct i2c_client *ara = adapter->ara; |
255 | |
256 | if (ara) { |
257 | dev_dbg(&ara->dev, "SMBus alert received\n" ); |
258 | i2c_handle_smbus_alert(ara); |
259 | } else |
260 | dev_dbg(&adapter->adapter.dev, |
261 | "SMBus alert received but no ARA client!\n" ); |
262 | } |
263 | |
264 | static void i2c_parport_attach(struct parport *port) |
265 | { |
266 | struct i2c_par *adapter; |
267 | int i; |
268 | struct pardev_cb i2c_parport_cb; |
269 | |
270 | if (type < 0) { |
271 | pr_warn("adapter type unspecified\n" ); |
272 | return; |
273 | } |
274 | |
275 | if (type >= ARRAY_SIZE(adapter_parm)) { |
276 | pr_warn("invalid type (%d)\n" , type); |
277 | return; |
278 | } |
279 | |
280 | for (i = 0; i < MAX_DEVICE; i++) { |
281 | if (parport[i] == -1) |
282 | continue; |
283 | if (port->number == parport[i]) |
284 | break; |
285 | } |
286 | if (i == MAX_DEVICE) { |
287 | pr_debug("Not using parport%d.\n" , port->number); |
288 | return; |
289 | } |
290 | |
291 | adapter = kzalloc(size: sizeof(struct i2c_par), GFP_KERNEL); |
292 | if (!adapter) |
293 | return; |
294 | memset(&i2c_parport_cb, 0, sizeof(i2c_parport_cb)); |
295 | i2c_parport_cb.flags = PARPORT_FLAG_EXCL; |
296 | i2c_parport_cb.irq_func = i2c_parport_irq; |
297 | i2c_parport_cb.private = adapter; |
298 | |
299 | pr_debug("attaching to %s\n" , port->name); |
300 | parport_disable_irq(port); |
301 | adapter->pdev = parport_register_dev_model(port, name: "i2c-parport" , |
302 | par_dev_cb: &i2c_parport_cb, cnt: i); |
303 | if (!adapter->pdev) { |
304 | pr_err("Unable to register with parport\n" ); |
305 | goto err_free; |
306 | } |
307 | |
308 | /* Fill the rest of the structure */ |
309 | adapter->adapter.owner = THIS_MODULE; |
310 | adapter->adapter.class = I2C_CLASS_HWMON; |
311 | strscpy(p: adapter->adapter.name, q: "Parallel port adapter" , |
312 | size: sizeof(adapter->adapter.name)); |
313 | adapter->algo_data = parport_algo_data; |
314 | /* Slow down if we can't sense SCL */ |
315 | if (!adapter_parm[type].getscl.val) { |
316 | adapter->algo_data.getscl = NULL; |
317 | adapter->algo_data.udelay = 50; /* ~10 kbps */ |
318 | } |
319 | adapter->algo_data.data = port; |
320 | adapter->adapter.algo_data = &adapter->algo_data; |
321 | adapter->adapter.dev.parent = port->physport->dev; |
322 | |
323 | if (parport_claim_or_block(dev: adapter->pdev) < 0) { |
324 | dev_err(&adapter->pdev->dev, |
325 | "Could not claim parallel port\n" ); |
326 | goto err_unregister; |
327 | } |
328 | |
329 | /* Reset hardware to a sane state (SCL and SDA high) */ |
330 | parport_setsda(data: port, state: 1); |
331 | parport_setscl(data: port, state: 1); |
332 | /* Other init if needed (power on...) */ |
333 | if (adapter_parm[type].init.val) { |
334 | line_set(data: port, state: 1, op: &adapter_parm[type].init); |
335 | /* Give powered devices some time to settle */ |
336 | msleep(msecs: 100); |
337 | } |
338 | |
339 | if (i2c_bit_add_bus(&adapter->adapter) < 0) { |
340 | dev_err(&adapter->pdev->dev, "Unable to register with I2C\n" ); |
341 | goto err_unregister; |
342 | } |
343 | |
344 | /* Setup SMBus alert if supported */ |
345 | if (adapter_parm[type].smbus_alert) { |
346 | struct i2c_client *ara; |
347 | |
348 | ara = i2c_new_smbus_alert_device(adapter: &adapter->adapter, |
349 | setup: &adapter->alert_data); |
350 | if (!IS_ERR(ptr: ara)) { |
351 | adapter->ara = ara; |
352 | parport_enable_irq(port); |
353 | } else { |
354 | dev_warn(&adapter->pdev->dev, |
355 | "Failed to register ARA client\n" ); |
356 | } |
357 | } |
358 | |
359 | /* Add the new adapter to the list */ |
360 | mutex_lock(&adapter_list_lock); |
361 | list_add_tail(new: &adapter->node, head: &adapter_list); |
362 | mutex_unlock(lock: &adapter_list_lock); |
363 | return; |
364 | |
365 | err_unregister: |
366 | parport_release(dev: adapter->pdev); |
367 | parport_unregister_device(dev: adapter->pdev); |
368 | err_free: |
369 | kfree(objp: adapter); |
370 | } |
371 | |
372 | static void i2c_parport_detach(struct parport *port) |
373 | { |
374 | struct i2c_par *adapter, *_n; |
375 | |
376 | /* Walk the list */ |
377 | mutex_lock(&adapter_list_lock); |
378 | list_for_each_entry_safe(adapter, _n, &adapter_list, node) { |
379 | if (adapter->pdev->port == port) { |
380 | if (adapter->ara) { |
381 | parport_disable_irq(port); |
382 | i2c_unregister_device(client: adapter->ara); |
383 | } |
384 | i2c_del_adapter(adap: &adapter->adapter); |
385 | |
386 | /* Un-init if needed (power off...) */ |
387 | if (adapter_parm[type].init.val) |
388 | line_set(data: port, state: 0, op: &adapter_parm[type].init); |
389 | |
390 | parport_release(dev: adapter->pdev); |
391 | parport_unregister_device(dev: adapter->pdev); |
392 | list_del(entry: &adapter->node); |
393 | kfree(objp: adapter); |
394 | } |
395 | } |
396 | mutex_unlock(lock: &adapter_list_lock); |
397 | } |
398 | |
399 | static struct parport_driver i2c_parport_driver = { |
400 | .name = "i2c-parport" , |
401 | .match_port = i2c_parport_attach, |
402 | .detach = i2c_parport_detach, |
403 | .devmodel = true, |
404 | }; |
405 | module_parport_driver(i2c_parport_driver); |
406 | |
407 | MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>" ); |
408 | MODULE_DESCRIPTION("I2C bus over parallel port" ); |
409 | MODULE_LICENSE("GPL" ); |
410 | |