public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 3/9]Four new i2c drivers and __init/__exit cleanup to i2c
@ 2002-09-15 22:37 Albert Cranford
  2002-09-15 23:06 ` Jeff Garzik
  0 siblings, 1 reply; 2+ messages in thread
From: Albert Cranford @ 2002-09-15 22:37 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Kernel mailing list

[-- Attachment #1: Type: TEXT/PLAIN, Size: 484 bytes --]

Hello Linus,
New I2C drivers that have been adjusted after Russell King comments of August.
o i2c-algo-8xx.c
o i2c-pport.c
o i2c-adap-ibm_ocp.c
o i2c-pcf-epp.c
o Add new drivers to Config.in and Makefile.
o Add new drivers to i2c-core for initialization.
o Remove EXPORT_NO_SYMBOLS statement from i2c-dev, i2c-elektor and i2c-frodo.
o Cleanup init_module and cleanup_module adding __init and __exit to most drivers.
o Adjust i2c-elektor with cli/sti replacement.
-- 
ac9410@attbi.com

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: TEXT/PLAIN; charset=X-UNKNOWN; name=47-i2c-3c-patch, Size: 12289 bytes --]

--- /dev/null	1994-07-17 19:46:18.000000000 -0400
+++ linux-2.5.34/drivers/i2c/i2c-adap-ibm_ocp.c	2002-08-07 22:38:57.000000000 -0400
@@ -0,0 +1,397 @@
+/*
+   -------------------------------------------------------------------------
+   i2c-adap-ibm_ocp.c i2c-hw access for the IIC peripheral on the IBM PPC 405
+   -------------------------------------------------------------------------
+  
+   Ian DaSilva, MontaVista Software, Inc.
+   idasilva@mvista.com or source@mvista.com
+
+   Copyright 2000 MontaVista Software Inc.
+
+   Changes made to support the IIC peripheral on the IBM PPC 405 
+
+
+   ----------------------------------------------------------------------------
+   This file was highly leveraged from i2c-elektor.c, which was created
+   by Simon G. Vogl and Hans Berglund:
+
+ 
+     Copyright (C) 1995-97 Simon G. Vogl
+                   1998-99 Hans Berglund
+
+   With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+   Frodo Looijaard <frodol@dds.nl>
+
+
+    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 program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   ----------------------------------------------------------------------------
+
+   History: 01/20/12 - Armin
+   	akuster@mvista.com
+   	ported up to 2.4.16+	
+
+   Version 02/03/25 - Armin
+       converted to ocp format
+       removed commented out or #if 0 code
+
+   TODO: convert to ocp_register
+         add PM hooks
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/i2c.h>
+#include "i2c-algo-ibm_ocp.h"
+#include <linux/i2c-id.h>
+#include <asm/ocp.h>
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+/*
+ * This next section is configurable, and it is used to set the number
+ * of i2c controllers in the system.  The default number of instances is 1,
+ * however, this should be changed to reflect your system's configuration.
+ */ 
+
+/*
+ * The STB03xxx, with a PPC405 core, has two i2c controllers.
+ */
+//(sizeof(IIC_ADDR)/sizeof(struct iic_regs))
+extern iic_t *IIC_ADDR[];
+static struct iic_ibm iic_ibmocp_adaps[IIC_NUMS][5];
+
+static struct i2c_algo_iic_data *iic_ibmocp_data[IIC_NUMS];
+static struct i2c_adapter *iic_ibmocp_ops[IIC_NUMS];
+
+static int i2c_debug=0;
+static wait_queue_head_t iic_wait[IIC_NUMS];
+static int iic_pending;
+
+/* ----- global defines -----------------------------------------------	*/
+#define DEB(x)	if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x
+#define DEBE(x)	x	/* error messages 				*/
+
+/* ----- local functions ----------------------------------------------	*/
+
+//
+// Description: Write a byte to IIC hardware
+//
+static void iic_ibmocp_setbyte(void *data, int ctl, int val)
+{
+   // writeb resolves to a write to the specified memory location
+   // plus a call to eieio.  eieio ensures that all instructions
+   // preceding it are completed before any further stores are
+   // completed.
+   // Delays at this level (to protect writes) are not needed here.
+   writeb(val, ctl);
+}
+
+
+//
+// Description: Read a byte from IIC hardware
+//
+static int iic_ibmocp_getbyte(void *data, int ctl)
+{
+   int val;
+
+   val = readb(ctl);
+   return (val);
+}
+
+
+//
+// Description: Return our slave address.  This is the address
+// put on the I2C bus when another master on the bus wants to address us
+// as a slave
+//
+static int iic_ibmocp_getown(void *data)
+{
+   return(((struct iic_ibm *)(data))->iic_own);
+}
+
+
+//
+// Description: Return the clock rate
+//
+static int iic_ibmocp_getclock(void *data)
+{
+   return(((struct iic_ibm *)(data))->iic_clock);
+}
+
+
+#if 0
+static void iic_ibmocp_sleep(unsigned long timeout)
+{
+   schedule_timeout( timeout * HZ);
+}
+#endif
+
+
+//
+// Description:  Put this process to sleep.  We will wake up when the
+// IIC controller interrupts.
+//
+static void iic_ibmocp_waitforpin(void *data) {
+
+   int timeout = 2;
+   struct iic_ibm *priv_data = data;
+
+   //
+   // If interrupts are enabled (which they are), then put the process to
+   // sleep.  This process will be awakened by two events -- either the
+   // the IIC peripheral interrupts or the timeout expires. 
+   //
+   if (priv_data->iic_irq > 0) {
+      local_irq_disable();
+      if (iic_pending == 0) {
+  	 interruptible_sleep_on_timeout(&(iic_wait[priv_data->index]), timeout*HZ );
+      } else
+ 	 iic_pending = 0;
+      local_irq_enable();
+   } else {
+      //
+      // If interrupts are not enabled then delay for a reasonable amount
+      // of time and return.  We expect that by time we return to the calling
+      // function that the IIC has finished our requested transaction and
+      // the status bit reflects this.
+      //
+      // udelay is probably not the best choice for this since it is
+      // the equivalent of a busy wait
+      //
+      udelay(100);
+   }
+   //printk("iic_ibmocp_waitforpin: exitting\n");
+}
+
+
+//
+// Description: The registered interrupt handler
+//
+static void iic_ibmocp_handler(int this_irq, void *dev_id, struct pt_regs *regs) 
+{
+   int ret;
+   struct iic_regs *iic;
+   struct iic_ibm *priv_data = dev_id;
+   iic = (struct iic_regs *) priv_data->iic_base;
+   iic_pending = 1;
+   DEB2(printk("iic_ibmocp_handler: in interrupt handler\n"));
+   // Read status register
+   ret = readb((int) &(iic->sts));
+   DEB2(printk("iic_ibmocp_handler: status = %x\n", ret));
+   // Clear status register.  See IBM PPC 405 reference manual for details
+   writeb(0x0a, (int) &(iic->sts));
+   wake_up_interruptible(&(iic_wait[priv_data->index]));
+}
+
+
+//
+// Description: This function is very hardware dependent.  First, we lock
+// the region of memory where out registers exist.  Next, we request our
+// interrupt line and register its associated handler.  Our IIC peripheral
+// uses interrupt number 2, as specified by the 405 reference manual.
+//
+static int iic_hw_resrc_init(int instance)
+{
+
+   DEB(printk("iic_hw_resrc_init: Physical Base address: 0x%x\n", (u32) IIC_ADDR[instance] ));
+   iic_ibmocp_adaps[instance]->iic_base = (u32)ioremap((unsigned long)IIC_ADDR[instance],PAGE_SIZE);
+
+   DEB(printk("iic_hw_resrc_init: ioremapped base address: 0x%x\n", iic_ibmocp_adaps[instance]->iic_base));
+
+   if (iic_ibmocp_adaps[instance]->iic_irq > 0) {
+	
+      if (request_irq(iic_ibmocp_adaps[instance]->iic_irq, iic_ibmocp_handler,
+       0, "IBM OCP IIC", iic_ibmocp_adaps[instance]) < 0) {
+         printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n",
+          iic_ibmocp_adaps[instance]->iic_irq);
+	 iic_ibmocp_adaps[instance]->iic_irq = 0;
+      } else {
+         DEB3(printk("iic_hw_resrc_init: Enabled interrupt\n"));
+      }
+   }
+   return 0;
+}
+
+
+//
+// Description: Release irq and memory
+//
+static void iic_ibmocp_release(void)
+{
+   int i;
+
+   for(i=0; i<IIC_NUMS; i++) {
+      struct iic_ibm *priv_data = (struct iic_ibm *)iic_ibmocp_data[i]->data;
+      if (priv_data->iic_irq > 0) {
+         disable_irq(priv_data->iic_irq);
+         free_irq(priv_data->iic_irq, 0);
+      }
+      kfree(iic_ibmocp_data[i]);
+      kfree(iic_ibmocp_ops[i]);
+   }
+}
+
+
+//
+// Description: Does nothing
+//
+static int iic_ibmocp_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+
+//
+// Description: Does nothing
+//
+static int iic_ibmocp_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+
+//
+// Description: If this compiled as a module, then increment the count
+//
+static void iic_ibmocp_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+
+//
+// Description: If this is a module, then decrement the count
+//
+static void iic_ibmocp_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+//
+// Description: Called when the module is loaded.  This function starts the
+// cascade of calls up through the heirarchy of i2c modules (i.e. up to the
+//  algorithm layer and into to the core layer)
+//
+int __init iic_ibmocp_init(void) 
+{
+   int i;
+
+   printk(KERN_INFO "iic_ibmocp_init: IBM on-chip iic adapter module\n");
+ 
+   for(i=0; i<IIC_NUMS; i++) {
+      iic_ibmocp_data[i] = kmalloc(sizeof(struct i2c_algo_iic_data),GFP_KERNEL);
+      if(iic_ibmocp_data[i] == NULL) {
+         return -ENOMEM;
+      }
+      memset(iic_ibmocp_data[i], 0, sizeof(struct i2c_algo_iic_data));
+      
+      switch (i) {
+	      case 0:
+	       iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(0);
+	      break;
+	      case 1:
+	       iic_ibmocp_adaps[i]->iic_irq = IIC_IRQ(1);
+	      break;
+      }
+      iic_ibmocp_adaps[i]->iic_clock = IIC_CLOCK;
+      iic_ibmocp_adaps[i]->iic_own = IIC_OWN; 
+      iic_ibmocp_adaps[i]->index = i;
+ 
+      DEB(printk("irq %x\n", iic_ibmocp_adaps[i]->iic_irq));
+      DEB(printk("clock %x\n", iic_ibmocp_adaps[i]->iic_clock));
+      DEB(printk("own %x\n", iic_ibmocp_adaps[i]->iic_own));
+      DEB(printk("index %x\n", iic_ibmocp_adaps[i]->index));
+
+
+      iic_ibmocp_data[i]->data = (struct iic_regs *)iic_ibmocp_adaps[i]; 
+      iic_ibmocp_data[i]->setiic = iic_ibmocp_setbyte;
+      iic_ibmocp_data[i]->getiic = iic_ibmocp_getbyte;
+      iic_ibmocp_data[i]->getown = iic_ibmocp_getown;
+      iic_ibmocp_data[i]->getclock = iic_ibmocp_getclock;
+      iic_ibmocp_data[i]->waitforpin = iic_ibmocp_waitforpin;
+      iic_ibmocp_data[i]->udelay = 80;
+      iic_ibmocp_data[i]->mdelay = 80;
+      iic_ibmocp_data[i]->timeout = 100;
+      
+            iic_ibmocp_ops[i] = kmalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+      if(iic_ibmocp_ops[i] == NULL) {
+         return -ENOMEM;
+      }
+      memset(iic_ibmocp_ops[i], 0, sizeof(struct i2c_adapter));
+      strcpy(iic_ibmocp_ops[i]->name, "IBM OCP IIC adapter");
+      iic_ibmocp_ops[i]->id = I2C_HW_OCP;
+      iic_ibmocp_ops[i]->algo = NULL;
+      iic_ibmocp_ops[i]->algo_data = iic_ibmocp_data[i];
+      iic_ibmocp_ops[i]->inc_use = iic_ibmocp_inc_use;
+      iic_ibmocp_ops[i]->dec_use = iic_ibmocp_dec_use;
+      iic_ibmocp_ops[i]->client_register = iic_ibmocp_reg;
+      iic_ibmocp_ops[i]->client_unregister = iic_ibmocp_unreg;
+       
+      
+      init_waitqueue_head(&(iic_wait[i]));
+      if (iic_hw_resrc_init(i) == 0) {
+         if (i2c_iic_add_bus(iic_ibmocp_ops[i]) < 0)
+         return -ENODEV;
+      } else {
+         return -ENODEV;
+      }
+      DEB(printk(KERN_INFO "iic_ibmocp_init: found device at %#x.\n\n", iic_ibmocp_adaps[i]->iic_base));
+   }
+   return 0;
+}
+
+
+static void iic_ibmocp_exit(void)
+{
+   int i;
+
+   for(i=0; i<IIC_NUMS; i++) {
+      i2c_iic_del_bus(iic_ibmocp_ops[i]);
+   }
+   iic_ibmocp_release();
+}
+
+//
+// If modules is NOT defined when this file is compiled, then the MODULE_*
+// macros will resolve to nothing
+//
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PPC 405 IIC bus adapter");
+MODULE_PARM(base, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(clock, "i");
+MODULE_PARM(own, "i");
+MODULE_PARM(i2c_debug,"i");
+
+
+module_init(iic_ibmocp_init);
+module_exit(iic_ibmocp_exit); 

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2002-09-15 23:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-09-15 22:37 [patch 3/9]Four new i2c drivers and __init/__exit cleanup to i2c Albert Cranford
2002-09-15 23:06 ` Jeff Garzik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox