patch-2.3.4 linux/drivers/char/i2c-parport.c

Next file: linux/drivers/char/keyboard.c
Previous file: linux/drivers/char/cyclades.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.3/linux/drivers/char/i2c-parport.c linux/drivers/char/i2c-parport.c
@@ -0,0 +1,149 @@
+/*
+ * I2C driver for parallel port
+ *
+ * Author: Phil Blundell <philb@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This driver implements a simple I2C protocol by bit-twiddling some
+ * signals on the parallel port.  Since the outputs on the parallel port
+ * aren't open collector, three lines rather than two are used:
+ *
+ *	D0	clock out
+ *	D1	data out
+ *	BUSY	data in	
+ */
+
+#include <linux/parport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <asm/spinlock.h>
+
+#define I2C_DELAY   10
+
+static int debug = 0;
+
+struct parport_i2c_bus
+{
+  struct i2c_bus i2c;
+  struct parport_i2c_bus *next;
+};
+
+static struct parport_i2c_bus *bus_list;
+
+#ifdef __SMP__
+static spinlock_t bus_list_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus, int clk, int data)
+{
+  struct parport *p = bus->data;
+  parport_write_data(p, (clk?1:0) | (data?2:0)); 
+  udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+  struct parport *p = bus->data;
+  return (parport_read_status(p) & PARPORT_STATUS_BUSY) ? 0 : 1;
+}
+
+static struct i2c_bus parport_i2c_bus_template = 
+{
+  "...",
+  I2C_BUSID_PARPORT,
+  NULL,
+  
+  SPIN_LOCK_UNLOCKED,
+  
+  NULL,
+  NULL,
+	
+  i2c_setlines,
+  i2c_getdataline,
+  NULL,
+  NULL,
+};
+
+static void i2c_parport_attach(struct parport *port)
+{
+  struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), 
+				      GFP_KERNEL);
+  b->i2c = parport_i2c_bus_template;
+  b->i2c.data = port;
+  strncpy(b->i2c.name, port->name, 32);
+  spin_lock(&bus_list_lock);
+  b->next = bus_list;
+  bus_list = b;
+  spin_unlock(&bus_list_lock);
+  i2c_register_bus(&b->i2c);
+  if (debug)
+    printk(KERN_DEBUG "i2c: attached to %s\n", port->name);
+}
+
+static void i2c_parport_detach(struct parport *port)
+{
+  struct parport_i2c_bus *b, *old_b = NULL;
+  spin_lock(&bus_list_lock);
+  b = bus_list;
+  while (b)
+  {
+    if (b->i2c.data == port)
+    {
+      if (old_b)
+	old_b->next = b->next;
+      else
+	bus_list = b->next;
+      i2c_unregister_bus(&b->i2c);
+      kfree(b);
+      break;
+    }
+    old_b = b;
+    b = b->next;
+  }
+  spin_unlock(&bus_list_lock);
+  if (debug)
+    printk(KERN_DEBUG "i2c: detached from %s\n", port->name);
+}
+
+static struct parport_driver parport_i2c_driver = 
+{
+  "i2c",
+  i2c_parport_attach,
+  i2c_parport_detach
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int __init i2c_parport_init(void)
+#endif
+{
+  printk("I2C: driver for parallel port v0.1 philb@gnu.org\n");
+  parport_register_driver(&parport_i2c_driver);
+  return 0;
+}
+
+#ifdef MODULE
+MODULE_PARM(debug, "i");
+
+void cleanup_module(void)
+{
+  struct parport_i2c_bus *b = bus_list;
+  while (b)
+  {
+    struct parport_i2c_bus *next = b->next;
+    i2c_unregister_bus(&b->i2c);
+    kfree(b);
+    b = next;
+  }
+  parport_unregister_driver(&parport_i2c_driver);
+}
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)