1 /*
2  * I2C driver for parallel port
3  *
4  * Author: Phil Blundell <philb@gnu.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  *
11  * This driver implements a simple I2C protocol by bit-twiddling some
12  * signals on the parallel port.  Since the outputs on the parallel port
13  * aren't open collector, three lines rather than two are used:
14  *
15  *	D0	clock out
16  *	D1	data out
17  *	BUSY	data in
18  */
19 
20 #include <linux/parport.h>
21 #include <linux/module.h>
22 #include <linux/delay.h>
23 #include <linux/i2c-old.h>
24 #include <linux/init.h>
25 #include <linux/spinlock.h>
26 
27 #define I2C_DELAY   10
28 
29 static int debug = 0;
30 
31 struct parport_i2c_bus
32 {
33   struct i2c_bus i2c;
34   struct parport_i2c_bus *next;
35 };
36 
37 static struct parport_i2c_bus *bus_list;
38 
39 static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED;
40 
41 /* software I2C functions */
42 
i2c_setlines(struct i2c_bus * bus,int clk,int data)43 static void i2c_setlines(struct i2c_bus *bus, int clk, int data)
44 {
45   struct parport *p = bus->data;
46   parport_write_data(p, (clk?1:0) | (data?2:0));
47   udelay(I2C_DELAY);
48 }
49 
i2c_getdataline(struct i2c_bus * bus)50 static int i2c_getdataline(struct i2c_bus *bus)
51 {
52   struct parport *p = bus->data;
53   return (parport_read_status(p) & PARPORT_STATUS_BUSY) ? 0 : 1;
54 }
55 
56 static struct i2c_bus parport_i2c_bus_template =
57 {
58   "...",
59   I2C_BUSID_PARPORT,
60   NULL,
61 
62   SPIN_LOCK_UNLOCKED,
63 
64   NULL,
65   NULL,
66 
67   i2c_setlines,
68   i2c_getdataline,
69   NULL,
70   NULL,
71 };
72 
i2c_parport_attach(struct parport * port)73 static void i2c_parport_attach(struct parport *port)
74 {
75   struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus),
76 				      GFP_KERNEL);
77   if (!b) {
78 	  printk(KERN_ERR "i2c_parport: Memory allocation failed. Not attaching.\n");
79 	  return;
80   }
81   b->i2c = parport_i2c_bus_template;
82   b->i2c.data = parport_get_port (port);
83   strncpy(b->i2c.name, port->name, 32);
84   spin_lock(&bus_list_lock);
85   b->next = bus_list;
86   bus_list = b;
87   spin_unlock(&bus_list_lock);
88   i2c_register_bus(&b->i2c);
89   if (debug)
90     printk(KERN_DEBUG "i2c: attached to %s\n", port->name);
91 }
92 
i2c_parport_detach(struct parport * port)93 static void i2c_parport_detach(struct parport *port)
94 {
95   struct parport_i2c_bus *b, *old_b = NULL;
96   spin_lock(&bus_list_lock);
97   b = bus_list;
98   while (b)
99   {
100     if (b->i2c.data == port)
101     {
102       if (old_b)
103 	old_b->next = b->next;
104       else
105 	bus_list = b->next;
106       i2c_unregister_bus(&b->i2c);
107       kfree(b);
108       break;
109     }
110     old_b = b;
111     b = b->next;
112   }
113   spin_unlock(&bus_list_lock);
114   if (debug)
115     printk(KERN_DEBUG "i2c: detached from %s\n", port->name);
116 }
117 
118 static struct parport_driver parport_i2c_driver =
119 {
120   "i2c",
121   i2c_parport_attach,
122   i2c_parport_detach
123 };
124 
125 #ifdef MODULE
init_module(void)126 int init_module(void)
127 #else
128 int __init i2c_parport_init(void)
129 #endif
130 {
131   printk("I2C: driver for parallel port v0.1 philb@gnu.org\n");
132   parport_register_driver(&parport_i2c_driver);
133   return 0;
134 }
135 
136 #ifdef MODULE
137 MODULE_PARM(debug, "i");
138 
cleanup_module(void)139 void cleanup_module(void)
140 {
141   struct parport_i2c_bus *b = bus_list;
142   while (b)
143   {
144     struct parport_i2c_bus *next = b->next;
145     i2c_unregister_bus(&b->i2c);
146     kfree(b);
147     b = next;
148   }
149   parport_unregister_driver(&parport_i2c_driver);
150 }
151 #endif
152 MODULE_LICENSE("GPL");
153