Re: irqdesc porting help

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,
 Sorry for the late response, attached is the code im trying to port
to linux - 2.6.20.


Regards,
Jo




On 2/15/07, Paul Mundt <[email protected]> wrote:
On Thu, Feb 15, 2007 at 12:01:37PM +0530, Maximus wrote:
> Im trying to port some drivers between 2.6.14 and 2.6.19
>
> I find that irqdesc has changed completely. how do i port
> the drivers between 2.6.14 and 2.6.19?
>
> is there a porting guide available to port the drivers
> which use irqdesc?.
>
> my drivers use variables triggered, ... which dont exist in 2.6.19
> irqdesc strcuture.
>
Presumably you're talking about the struct hw_interrupt_type and the lack
of an irq_desc[irq].handler? There's some migration helper glue in
include/linux/irq.h that you can use, but you're better off converting
completely. You can at least get it building again by changing to
irq_desc[irq].chip, but you really want a proper irq_chip implementation
to go along with this, rather than munging in the hw_interrupt_type.

You can easily compare before-and-after versions of most of the IRQ
controllers to identify the minimal changes required.

/*
 * linux/drivers/i2c/chips/twl4030_core.c
 *
 * Copyright (C) 2005-2006 Texas Instruments, Inc.
 *
 * Modifications to defer interrupt handling to a kernel thread:
 * Copyright (C) 2006 MontaVista Software, Inc.
 *
 * Based on tlv320aic23.c:
 * Copyright (c) by Kai Svahn <[email protected]>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

/*** Includes */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel_stat.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/random.h>
#include <linux/syscalls.h>
#include <linux/kthread.h>

#include <linux/i2c.h>
#include <linux/slab.h>

#include <asm/arch/twl4030.h>
#include <asm/arch/irqs.h>
#include <asm/irq.h>
#include <asm/arch/irq.h>
#include <asm/mach/irq.h>
#include <asm/arch/gpio.h>
//#include <asm/arch/platform.h>
#include <asm/arch/mux.h>
#include <asm/arch/power_companion.h>

#include <linux/device.h>
#include <asm/arch/bus.h>

#define CONFIG_TWL4030_IRQ_PRIO 26

/**** Macro Definitions */
#define TWL_CLIENT_STRING                        "TWL4030-ID"
#define TWL_CLIENT_USED                          1
#define TWL_CLIENT_FREE                          0

/* IRQ Flags */
#define FREE                                     0
#define USED                                     1

/** Primary Interrupt Handler on TWL4030 Registers */

/**** Register Definitions */

#define REG_PIH_ISR_P1                           (0x1)
#define REG_PIH_ISR_P2                           (0x2)
#define REG_PIH_SIR                              (0x3)

/**** BitField Definitions */

/* PIH_ISR_P1 Fields */
#define BIT_PIH_ISR_P1_PIH_ISR0                  (0x000)
#define BIT_PIH_ISR_P1_PIH_ISR0_M                (0x00000001)
#define BIT_PIH_ISR_P1_PIH_ISR1                  (0x001)
#define BIT_PIH_ISR_P1_PIH_ISR1_M                (0x00000002)
#define BIT_PIH_ISR_P1_PIH_ISR2                  (0x002)
#define BIT_PIH_ISR_P1_PIH_ISR2_M                (0x00000004)
#define BIT_PIH_ISR_P1_PIH_ISR3                  (0x003)
#define BIT_PIH_ISR_P1_PIH_ISR3_M                (0x00000008)
#define BIT_PIH_ISR_P1_PIH_ISR4                  (0x004)
#define BIT_PIH_ISR_P1_PIH_ISR4_M                (0x00000010)
#define BIT_PIH_ISR_P1_PIH_ISR5                  (0x005)
#define BIT_PIH_ISR_P1_PIH_ISR5_M                (0x00000020)
#define BIT_PIH_ISR_P1_PIH_ISR6                  (0x006)
#define BIT_PIH_ISR_P1_PIH_ISR6_M                (0x00000040)
#define BIT_PIH_ISR_P1_PIH_ISR7                  (0x007)
#define BIT_PIH_ISR_P1_PIH_ISR7_M                (0x00000080)
/* PIH_ISR_P2 Fields */
#define BIT_PIH_ISR_P2_PIH_ISR0                  (0x000)
#define BIT_PIH_ISR_P2_PIH_ISR0_M                (0x00000001)
#define BIT_PIH_ISR_P2_PIH_ISR1                  (0x001)
#define BIT_PIH_ISR_P2_PIH_ISR1_M                (0x00000002)
#define BIT_PIH_ISR_P2_PIH_ISR2                  (0x002)
#define BIT_PIH_ISR_P2_PIH_ISR2_M                (0x00000004)
#define BIT_PIH_ISR_P2_PIH_ISR3                  (0x003)
#define BIT_PIH_ISR_P2_PIH_ISR3_M                (0x00000008)
#define BIT_PIH_ISR_P2_PIH_ISR4                  (0x004)
#define BIT_PIH_ISR_P2_PIH_ISR4_M                (0x00000010)
#define BIT_PIH_ISR_P2_PIH_ISR5                  (0x005)
#define BIT_PIH_ISR_P2_PIH_ISR5_M                (0x00000020)
#define BIT_PIH_ISR_P2_PIH_ISR6                  (0x006)
#define BIT_PIH_ISR_P2_PIH_ISR6_M                (0x00000040)
#define BIT_PIH_ISR_P2_PIH_ISR7                  (0x007)
#define BIT_PIH_ISR_P2_PIH_ISR7_M                (0x00000080)
/* PIH_SIR Fields */
#define BIT_PIH_SIR_PIH1SIR                      (0x000)
#define BIT_PIH_SIR_PIH1SIR_M                    (0x00000001)
#define BIT_PIH_SIR_PIH2SIR                      (0x001)
#define BIT_PIH_SIR_PIH2SIR_M                    (0x00000002)
#define BIT_PIH_SIR_PIH3SIR                      (0x002)
#define BIT_PIH_SIR_PIH3SIR_M                    (0x00000004)
#define BIT_PIH_SIR_PIH4SIR                      (0x003)
#define BIT_PIH_SIR_PIH4SIR_M                    (0x00000008)
#define BIT_PIH_SIR_PIH5SIR                      (0x004)
#define BIT_PIH_SIR_PIH5SIR_M                    (0x00000010)
#define BIT_PIH_SIR_PIH6SIR                      (0x005)
#define BIT_PIH_SIR_PIH6SIR_M                    (0x00000020)

/* Triton Core internal information (BEGIN) */

/* Last - for index max*/
#define TWL4030_MODULE_LAST         TWL4030_MODULE_SECURED_REG

/* Slave address */
#define TWL4030_NUM_SLAVES          0x04
#define TWL4030_SLAVENUM_NUM0       0x00
#define TWL4030_SLAVENUM_NUM1       0x01
#define TWL4030_SLAVENUM_NUM2       0x02
#define TWL4030_SLAVENUM_NUM3       0x03
#define TWL4030_SLAVEID_ID0         0x48
#define TWL4030_SLAVEID_ID1         0x49
#define TWL4030_SLAVEID_ID2         0x4A
#define TWL4030_SLAVEID_ID3         0x4B

/* Base Address defns */
/* USB ID */
#define TWL4030_BASEADD_USB         0x0000
/* AUD ID */
#define TWL4030_BASEADD_AUDIO_VOICE 0x0000

/* M1 companion board GPIO base address */
#ifdef CONFIG_TWL4030_CORE_M1
#define TWL4030_BASEADD_GPIO        0x0018
#elif CONFIG_TWL4030_CORE_T2
/* For T2 chip -Use this GPIO addr*/
#define TWL4030_BASEADD_GPIO        0x0098
#endif

#define TWL4030_BASEADD_INTBR       0x0085
#define TWL4030_BASEADD_PIH         0x0080
#define TWL4030_BASEADD_TEST        0x004C
/* AUX ID */
#define TWL4030_BASEADD_INTERRUPTS  0x00B9
#define TWL4030_BASEADD_LED         0x00EE
#define TWL4030_BASEADD_MADC        0x0000
#define TWL4030_BASEADD_MAIN_CHARGE 0x0074
#define TWL4030_BASEADD_PRECHARGE   0x00AA
#define TWL4030_BASEADD_PWM0        0x00F8
#define TWL4030_BASEADD_PWM1        0x00FB
#define TWL4030_BASEADD_PWMA        0x00EF
#define TWL4030_BASEADD_PWMB        0x00F1
#define TWL4030_BASEADD_KEYPAD      0x00D2
/* POWER ID */
#define TWL4030_BASEADD_BACKUP      0x0014
#define TWL4030_BASEADD_INT         0x002E
#define TWL4030_BASEADD_PM_MASTER   0x0036
#define TWL4030_BASEADD_PM_RECIEVER 0x005B
#define TWL4030_BASEADD_RTC         0x001C
#define TWL4030_BASEADD_SECURED_REG 0x0000

/* Triton Core internal information (END) */

/* Pull out the board specific config's defines */
#ifdef CONFIG_TWL4030_CORE_M1
/* M1 companion board with FPGA acting as T2 */
#define CONFIG_I2C_TWL4030_ID0 CONFIG_I2C_TWL4030_M1_ID0
#define CONFIG_I2C_TWL4030_ID1 CONFIG_I2C_TWL4030_M1_ID1
#define CONFIG_I2C_TWL4030_ID2 CONFIG_I2C_TWL4030_M1_ID2
#define CONFIG_I2C_TWL4030_ID3 CONFIG_I2C_TWL4030_M1_ID3

#elif defined (CONFIG_TWL4030_CORE_T2)
/* The Real T2!! */
#define CONFIG_I2C_TWL4030_ID0 CONFIG_I2C_TWL4030_T2_ID0
#define CONFIG_I2C_TWL4030_ID1 CONFIG_I2C_TWL4030_T2_ID1
#define CONFIG_I2C_TWL4030_ID2 CONFIG_I2C_TWL4030_T2_ID2
#define CONFIG_I2C_TWL4030_ID3 CONFIG_I2C_TWL4030_T2_ID3
#else
#error "Unsupported platform!!!"
#endif


/* ----- debug defines ----------------------------------------------- */
/* Debug - four macros:
 * FN_IN, FN_OUT(value),D1,D2,D3 enabled based on log level
 */

/* Log level standard used here:
 * Log level 3 all messages
 * Log level 2 all entry-exit points
 * Log level 1 major messages
 * Log level 0 no messages
 */
#define TWL4030_LOG_LEVEL 0
/* detail - 0 - no detail
 *          1 - function name
 *          2 - function name, line number
 * prefix is added to every log message
 */
#define TWL4030_DETAIL    0

/* kernel log level*/
//#define TWL4030_K_LOG_LEVEL KERN_DEBUG
#define TWL4030_K_LOG_LEVEL

#if ( TWL4030_DETAIL > 0 )
#define DL1 "%s "
#define DR1 ,__FUNCTION__
#else
#define DL1
#define DR1
#endif
#if ( TWL4030_DETAIL > 1 )
#define DL2 "[%d] "
#define DR2 ,__LINE__
#else
#define DL2
#define DR2
#endif

#define D(format,...)\
	printk(TWL4030_K_LOG_LEVEL DL1 DL2 format "\n" DR1 DR2, ## __VA_ARGS__)

#if (TWL4030_LOG_LEVEL >= 1)
#define D1(ARGS...) D(ARGS)
#else
#define D1(ARGS...)
#endif
#if (TWL4030_LOG_LEVEL >= 2)
#define D2(ARGS...) D(ARGS)
#else
#define D2(ARGS...)
#endif
#if (TWL4030_LOG_LEVEL >= 3)
#define D3(ARGS...) D(ARGS)
#else
#define D3(ARGS...)
#endif

#if (TWL4030_LOG_LEVEL >= 2)
#define FN_IN printk("%s Entry\n",__FUNCTION__);
#define FN_OUT(ARG) printk("%s[%d]:Exit(%d)\n",__FUNCTION__,__LINE__,ARG);
#else
#define FN_IN
#define FN_OUT(ARG)
#endif

/* Sys FS Helper functions and macros */
#if CONFIG_I2C_TWL4030_DBG_SYSFS
/* Device Information- dummy */
static struct platform_device twl4030_debug_dev = {
	.name = TWL_CLIENT_STRING,
	.id = 0,
};

/* 255 Max bytes in a field register */
#define READ_REG_SIZE 255
/* Sys FS support */
static ssize_t show_mod(int mod, struct device *dev, char *buf)
{
	int j;
	unsigned char temp_buffer[READ_REG_SIZE + 1];
	struct timeval stv, stv1, stv2;
	int timespent1, timespent2;
	char *sval = buf;
	/* Read from I2c first 255 bytes (the max we can write in the reg) */
	do_gettimeofday(&stv);
	if ((j = twl4030_i2c_read(mod, temp_buffer, 0x0, READ_REG_SIZE)) < 0) {
		printk(KERN_ERR
		       "unable to read %d bytes returned %d in module %d\n",
		       READ_REG_SIZE, j, mod);
		return j;
	}
	do_gettimeofday(&stv1);
	/* do a read of the last 256th byte */
	if ((j =
	     twl4030_i2c_read_u8(mod, temp_buffer + READ_REG_SIZE,
				 READ_REG_SIZE)) < 0) {
		printk(KERN_ERR
		       "unable to read %d reg returned %d in module %d\n",
		       READ_REG_SIZE, j, mod);
		return j;
	}
	do_gettimeofday(&stv2);
	sval += sprintf(sval, "  | ");
	for (j = 0; j < 0x10; j++) {
		sval += sprintf(sval, "%02X ", j);
	}
	sval += sprintf(sval, "\n--+");

	for (j = 0; j < 0x10; j++) {
		sval += sprintf(sval, " --");
	}

	sval += sprintf(sval, "\n00| ");

	for (j = 0; j <= READ_REG_SIZE; j++) {
		sval += sprintf(sval, "%02X", temp_buffer[j]);
		if (j < READ_REG_SIZE) {
			sval +=
			    ((j + 1) % 0x10) ? sprintf(sval,
						       " ") : sprintf(sval,
								      "\n%02X| ",
								      j + 1);
		}
	}
	timespent1 =
	    (stv1.tv_sec - stv.tv_sec) * 1000000 + (stv1.tv_usec - stv.tv_usec);
	timespent2 =
	    (stv2.tv_sec - stv1.tv_sec) * 1000000 + (stv2.tv_usec -
						     stv1.tv_usec);
	sval +=
	    sprintf(sval, "\nTime Taken(uSec): 255bytes=%d 1byte=%d\n", timespent1,
		    timespent2);
	sval += 1;
	*sval = 0;
	return sval - buf + 1;
}

/* MSB 8 bits are register address[module reg offset] and LSB 8 bits the value */
static ssize_t
set_mod(int mod, struct device *dev, const char *buf, size_t count)
{
	u16 val = (u16) simple_strtoul(buf, NULL, 16);
	printk("Reg=0x%02x, val=0x%02x,mod=%d\n", (val & 0xFF00) >> 8,
	       (val & 0x00FF), mod);
	if (twl4030_i2c_write_u8(mod, (val & 0x00FF), (val & 0xFF00) >> 8) < 0) {
		printk("FAILED\n");
	} else {
		printk("SUCCESS\n");
	}
	return count;
}

/* function generator macros */
#define C_SHOW_MOD(MOD)\
static ssize_t show_mod##MOD( struct device *dev, char *buf)\
{\
	return show_mod(MOD, dev, buf);\
}\

#define C_SET_MOD(MOD)\
static ssize_t set_mod##MOD(struct device *dev, const char *buf, size_t count)\
{\
	return set_mod(MOD, dev, buf, count);\
}\

#define MAK_MOD(MOD) \
C_SET_MOD(MOD)\
C_SHOW_MOD(MOD)\
static DEVICE_ATTR(twl4030_mod##MOD, S_IWUSR | S_IRUGO, show_mod##MOD, set_mod##MOD);\

#define TWL4030_SYS_DEV_CREAT(MOD)\
		device_create_file(&twl4030_debug_dev.dev, &dev_attr_twl4030_mod##MOD);

MAK_MOD(0)
    MAK_MOD(1)
    MAK_MOD(2)
    MAK_MOD(3)
    MAK_MOD(4)
    MAK_MOD(5)
    MAK_MOD(6)
    MAK_MOD(7)
    MAK_MOD(8)
    MAK_MOD(9)
    MAK_MOD(10)
    MAK_MOD(11)
    MAK_MOD(12)
    MAK_MOD(13)
    MAK_MOD(14)
    MAK_MOD(15)
    MAK_MOD(16)
    MAK_MOD(17)
    MAK_MOD(18)
    MAK_MOD(19)
    MAK_MOD(20)
    MAK_MOD(21)
#define TWL_SYS_DEV()\
	TWL4030_SYS_DEV_CREAT(0)\
	TWL4030_SYS_DEV_CREAT(1)\
	TWL4030_SYS_DEV_CREAT(2)\
	TWL4030_SYS_DEV_CREAT(3)\
	TWL4030_SYS_DEV_CREAT(4)\
	TWL4030_SYS_DEV_CREAT(5)\
	TWL4030_SYS_DEV_CREAT(6)\
	TWL4030_SYS_DEV_CREAT(7)\
	TWL4030_SYS_DEV_CREAT(8)\
	TWL4030_SYS_DEV_CREAT(9)\
	TWL4030_SYS_DEV_CREAT(10)\
	TWL4030_SYS_DEV_CREAT(11)\
	TWL4030_SYS_DEV_CREAT(12)\
	TWL4030_SYS_DEV_CREAT(13)\
	TWL4030_SYS_DEV_CREAT(14)\
	TWL4030_SYS_DEV_CREAT(15)\
	TWL4030_SYS_DEV_CREAT(16)\
	TWL4030_SYS_DEV_CREAT(17)\
	TWL4030_SYS_DEV_CREAT(18)\
	TWL4030_SYS_DEV_CREAT(19)\
	TWL4030_SYS_DEV_CREAT(20)\
	TWL4030_SYS_DEV_CREAT(21)\


#endif
/**** Helper functions */
static int
twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid);
static int twl4030_attach_adapter(struct i2c_adapter *adapter);
static int twl4030_detach_client(struct i2c_client *client);
static void do_twl4030_irq(unsigned int irq, struct irqdesc *desc,
			   struct pt_regs *regs);

static void twl_init_irq(void);

/**** Data Structures */
/* To have info on T2 IRQ substem activated or not */
static unsigned char twl_irq_used = FREE;

/* Structure to define on TWL4030 Slave ID */
struct twl4030_client {
	struct i2c_client client;
	const char client_name[sizeof(TWL_CLIENT_STRING) + 1];
	const unsigned char address;
	const char adapter_index;
	unsigned char inuse;
	struct i2c_msg xfer_msg[2];	/* max numb of i2c_msg required is for read =2 */
	struct semaphore xfer_lock;	/* To lock access to xfer_msg */
};

/* Module Mapping */
struct twl4030mapping {
	unsigned char sid;	/* Slave ID */
	unsigned char base;	/* base address */
};

/* mapping the module id to slave id and base address */
static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
	{TWL4030_SLAVENUM_NUM0,
	 TWL4030_BASEADD_USB /* TWL4030_MODULE_USB        */ },

	{TWL4030_SLAVENUM_NUM1,
	 TWL4030_BASEADD_AUDIO_VOICE /* TWL4030_MODULE_AUDIO_VOICE */ },

	{TWL4030_SLAVENUM_NUM1,
	 TWL4030_BASEADD_GPIO /* TWL4030_MODULE_GPIO       */ },

	{TWL4030_SLAVENUM_NUM1,
	 TWL4030_BASEADD_INTBR /* TWL4030_MODULE_INTBR      */ },

	{TWL4030_SLAVENUM_NUM1,
	 TWL4030_BASEADD_PIH /* TWL4030_MODULE_PIH        */ },

	{TWL4030_SLAVENUM_NUM1,
	 TWL4030_BASEADD_TEST /* TWL4030_MODULE_TEST       */ },

	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_KEYPAD /* TWL4030_MODULE_KEYPAD     */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_MADC /* TWL4030_MODULE_MADC       */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_INTERRUPTS /* TWL4030_MODULE_INTERRUPTS */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_LED /* TWL4030_MODULE_LED        */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_MAIN_CHARGE /* TWL4030_MODULE_MAIN_CHARGE */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_PRECHARGE /* TWL4030_MODULE_PRECHARGE  */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_PWM0 /* TWL4030_MODULE_PWM0       */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_PWM1 /* TWL4030_MODULE_PWM1       */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_PWMA /* TWL4030_MODULE_PWMA       */ },
	{TWL4030_SLAVENUM_NUM2,
	 TWL4030_BASEADD_PWMB /* TWL4030_MODULE_PWMB       */ },

	{TWL4030_SLAVENUM_NUM3,
	 TWL4030_BASEADD_BACKUP /* TWL4030_MODULE_BACKUP     */ },
	{TWL4030_SLAVENUM_NUM3,
	 TWL4030_BASEADD_INT /* TWL4030_MODULE_INT        */ },
	{TWL4030_SLAVENUM_NUM3,
	 TWL4030_BASEADD_PM_MASTER /* TWL4030_MODULE_PM_MASTER  */ },
	{TWL4030_SLAVENUM_NUM3,
	 TWL4030_BASEADD_PM_RECIEVER /* TWL4030_MODULE_PM_RECIEVER */ },
	{TWL4030_SLAVENUM_NUM3,
	 TWL4030_BASEADD_RTC /* TWL4030_MODULE_RTC        */ },
	{TWL4030_SLAVENUM_NUM3,
	 TWL4030_BASEADD_SECURED_REG /* TWL4030_MODULE_SECURED_REG */ },
};

static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES] = {
	{
	 .address = TWL4030_SLAVEID_ID0,
	 .client_name = TWL_CLIENT_STRING "0",
	 .adapter_index = CONFIG_I2C_TWL4030_ID0,},
	{
	 .address = TWL4030_SLAVEID_ID1,
	 .client_name = TWL_CLIENT_STRING "1",
	 .adapter_index = CONFIG_I2C_TWL4030_ID1,},
	{
	 .address = TWL4030_SLAVEID_ID2,
	 .client_name = TWL_CLIENT_STRING "2",
	 .adapter_index = CONFIG_I2C_TWL4030_ID2,},
	{
	 .address = TWL4030_SLAVEID_ID3,
	 .client_name = TWL_CLIENT_STRING "3",
	 .adapter_index = CONFIG_I2C_TWL4030_ID3,},
};

/* One Client Driver , 4 Clients */
static struct i2c_driver twl4030_driver = {
	.name = "TWL4030",
	.id = I2C_DRIVERID_EXP0,	/* Experimental ID */
	.flags = I2C_DF_NOTIFY,
	.attach_adapter = twl4030_attach_adapter,
	.detach_client = twl4030_detach_client,
};

/* unique client id */
static unsigned int twl4030_id;

/* TWL4030 doesn't have PIH mask,
 * hence dummy function for mask
 * and unmask.
 */

static void twl4030_i2c_ackirq(unsigned int irq){
	FN_IN;
	FN_OUT(0);
}	

static void twl4030_i2c_disableint(unsigned int irq){
	FN_IN;
	FN_OUT(0);
}

static void twl4030_i2c_enableint(unsigned int irq){
	FN_IN;
	FN_OUT(0);
}	
	
/* information for processing in the Work Item */
static struct irqchip twl4030_irq_chip = {
	.ack = twl4030_i2c_ackirq,
	.mask = twl4030_i2c_disableint,
	.unmask = twl4030_i2c_enableint,
};

/**** Global Functions */
/**
 * @brief twl4030_i2c_write - Writes a n bit register in  TWL4030
 *
 * @param mod_no - module number
 * @param *value - an array of num_bytes+1 containing data to write
 * IMPORTANT - Allocate value num_bytes+1 and valid data starts at
 *             Offset 1.
 * @param reg - register address (just offset will do)
 * @param num_bytes - number of bytes to transfer
 *
 * @return result of operation - 0 is success
 */
int twl4030_i2c_write(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)
{
	int ret;
	int sid;
	struct twl4030_client *client;
	struct i2c_msg *msg;
	FN_IN;
	if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
		printk(KERN_ERR "TWL4030: Invalid module Number\n");
		FN_OUT(EPERM);
		return -EPERM;
	}
	sid = twl4030_map[mod_no].sid;
	client = &(twl4030_modules[sid]);

	if (unlikely(client->inuse != TWL_CLIENT_USED)) {
		printk(KERN_ERR
		       "TWL4030: I2C Client[%d] is not initialized[%d]\n", sid,
		       __LINE__);
		FN_OUT(EPERM);
		return -EPERM;
	}
	down(&(client->xfer_lock));
	/* [MSG1]: fill the register address data 
	 * fill the data Tx buffer 
	 */
	msg = &(client->xfer_msg[0]);
	msg->addr = client->address;
	if ((client->client.flags & I2C_M_HS) == I2C_M_HS)
		/* DO HS Mode transfer */
		msg->flags = I2C_M_WR | I2C_M_HS;	/* write the register value */
	else
		msg->flags = I2C_M_WR;	/* write the register value */
	
	msg->len = num_bytes + 1;	/* only one value */
	msg->buf = value;
	/* over write the first byte of buffer with the register address */
	*value = twl4030_map[mod_no].base + reg;
	ret = i2c_transfer(client->client.adapter, client->xfer_msg, 1);	/* one message */
	up(&(client->xfer_lock));
	/* i2cTransfer returns num messages.translate it pls.. */
	if (ret>=0)
		ret=0;
	FN_OUT(ret);
	return ret;
}

/**
 * @brief twl4030_i2c_read - Reads a n bit register in  TWL4030
 *
 * @param mod_no - module number
 * @param *value - an array of num_bytes containing data to be read
 * @param reg - register address (just offset will do)
 * @param num_bytes - number of bytes to transfer
 *
 * @return result of operation - num_bytes is success else failure.
 */
int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)
{
	int ret;
	u8 val;
	int sid;
	struct twl4030_client *client;
	struct i2c_msg *msg;
	FN_IN;
	if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
		printk(KERN_ERR "TWL4030: Invalid module Number\n");
		FN_OUT(EPERM);
		return -EPERM;
	}
	sid = twl4030_map[mod_no].sid;
	client = &(twl4030_modules[sid]);

	if (unlikely(client->inuse != TWL_CLIENT_USED)) {
		printk(KERN_ERR
		       "TWL4030: I2C Client[%d] is not initialized[%d]\n", sid,
		       __LINE__);
		FN_OUT(EPERM);
		return -EPERM;
	}
	down(&(client->xfer_lock));
	/* [MSG1] fill the register address data */
	msg = &(client->xfer_msg[0]);
	msg->addr = client->address;
	if ((client->client.flags & I2C_M_HS) == I2C_M_HS)
		msg->flags = I2C_M_WR | I2C_M_HS;	/* Read the register value in HS mode */
	else
		msg->flags = I2C_M_WR;	/* Read the register value */

	msg->len = 1;		/* only one value */
	val = twl4030_map[mod_no].base + reg;
	msg->buf = &val;
	/* [MSG2] fill the data rx buffer */
	msg = &(client->xfer_msg[1]);
	msg->addr = client->address;
	if ((client->client.flags & I2C_M_HS) == I2C_M_HS)
		msg->flags = I2C_M_RD | I2C_M_HS;	/* Read the register value in HS mode */
	else
		msg->flags = I2C_M_RD;	/* Read the register value */
	msg->len = num_bytes;	/* only n bytes */
	msg->buf = value;
	ret = i2c_transfer(client->client.adapter, client->xfer_msg, 2);	/* two messages */
	up(&(client->xfer_lock));
	/* i2cTransfer returns num messages.translate it pls.. */
	if (ret>=0)
		ret=0;
	FN_OUT(ret);
	return ret;
}

/**
 * @brief twl4030_i2c_write_u8 - Writes a 8 bit register in  TWL4030
 *
 * @param mod_no - module number
 * @param value - the value to be written 8 bit
 * @param reg - register address (just offset will do)
 *
 * @return result of operation - 0 is success
 */
int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
{
	int ret;
	/* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
	u8 temp_buffer[2]={0};
	FN_IN;
	/* offset 1 contains the data */
	temp_buffer[1]=value;
	ret = twl4030_i2c_write(mod_no,temp_buffer,reg,1) ;
	FN_OUT(ret);
	return ret;
}

/**
 * @brief twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
 *
 * @param mod_no - module number
 * @param *value - the value read 8 bit
 * @param reg - register address (just offset will do)
 *
 * @return result of operation - 0 is success
 */
int twl4030_i2c_read_u8(u8 mod_no, u8 * value, u8 reg)
{
	int ret=0;
	FN_IN;
	ret = twl4030_i2c_read(mod_no,value,reg,1);
	FN_OUT(ret);
	return ret;
}

/**** Helper Functions */

/*
 * do_twl4030_module_irq() is the desc->handle method for each of the twl4030 
 * module interrupts.  It executes in kernel thread context.
 * On entry, cpu interrupts are disabled.
 */
static void do_twl4030_module_irq(unsigned int irq, struct irqdesc *desc,
			   struct pt_regs *regs)
{
	struct irqaction *action;
	const unsigned int cpu = smp_processor_id();

	desc->triggered = 1;

	/*
	 * The desc->handle method would normally call the desc->chip->ack 
	 * method here, but we won't bother since our ack method is NULL.
	 */
	printk (KERN_INFO "do twl_module_irq\n") ;

	if (!desc->disable_depth) {
		kstat_cpu(cpu).irqs[irq]++;

		action = desc->action;
		if (action) {
			int ret;
			int status = 0;
			int retval = 0;

			//desc->status |= IRQ_INPROGRESS;

			local_irq_enable();

			do {
				/* Call the ISR with cpu interrupts enabled. */
				printk (KERN_INFO "Calling Handler\n") ;
				ret = action->handler(irq, action->dev_id, 
					regs);
				if (ret == IRQ_HANDLED)
					status |= action->flags;
				retval |= ret;
				action = action->next;
			} while (action);
		
			if (status & SA_SAMPLE_RANDOM)
				add_interrupt_randomness(irq);
	
			local_irq_disable();

			if (retval != IRQ_HANDLED) {
				printk(KERN_ERR "ISR for TWL4030 module"
					" irq %d can't handle interrupt\n", 
					irq);
			}

			/*
			 * Here is where we should call the unmask method, but 
			 * again we won't bother since it is NULL.
			 */
		} else {
			printk(KERN_CRIT "TWL4030 module irq %d has no ISR"
				" but can't be masked!\n", irq);
		}
		//desc->status &= ~IRQ_INPROGRESS;
	} else {
		printk(KERN_CRIT "TWL4030 module irq %d is disabled but can't"
			" be masked!\n", irq);
	}
}

/*
 * twl4030_irq_thread() runs as a kernel thread.  It queries the twl4030 
 * interrupt controller to see which modules are generating interrupt requests 
 * and then calls the desc->handle method for each module requesting service.
 */
static int twl4030_irq_thread(void *data)
{
	struct sched_param param;
	int irq = (int) data;
	struct irqdesc *desc = irq_desc + irq;
	static unsigned i2c_errors;
	const static unsigned max_i2c_errors = 100;

	current->flags |= PF_NOFREEZE;

	param.sched_priority = CONFIG_TWL4030_IRQ_PRIO;
	sys_sched_setscheduler(current->pid, SCHED_FIFO, &param);

	while (!kthread_should_stop()) {
		int ret;
		int module_irq;
		u8 pih_isr;

		ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr, 
			REG_PIH_ISR_P1);
		if (ret) {
			printk(KERN_WARNING "I2C error %d while reading TWL4030"
				" PIH ISR register.\n", ret);
			if (++i2c_errors >= max_i2c_errors) {
				printk(KERN_ERR "Maximum I2C error count"
					" exceeded.  Terminating %s.\n", 
					__FUNCTION__);
				break;
			}
			continue;
		}

		for (module_irq = IH_TWL4030_BASE; 0 != pih_isr; 
			pih_isr >>= 1, module_irq++)
		{
			if (pih_isr & 0x1) {
				struct irqdesc *d = irq_desc + module_irq;

				local_irq_disable();

				d->handle(module_irq, d, NULL);

				local_irq_enable();
			}
		}

		local_irq_disable();

		//desc->status &= ~IRQ_INPROGRESS;
		set_current_state(TASK_INTERRUPTIBLE);
		desc->chip->unmask(irq);

		local_irq_enable();

		schedule();
	}
	set_current_state(TASK_RUNNING);
	return 0;
}

/*
 * do_twl4030_irq() is the desc->handle method for the twl4030 interrupt.
 * This is a chained interrupt, so there is no desc->action method for it.
 * Now we need to query the interrupt controller in the twl4030 to determine 
 * which module is generating the interrupt request.  However, we can't do i2c 
 * transactions in interrupt context, so we must defer that work to a kernel 
 * thread.  All we do here is acknowledge and mask the interrupt and wakeup 
 * the kernel thread.
 */
static void do_twl4030_irq(unsigned int irq, struct irqdesc *desc,
			   struct pt_regs *regs)
{
	const unsigned int cpu = smp_processor_id();
	struct task_struct *thread = (struct task_struct *) desc->data;

	desc->triggered = 1;

	/*
	 * Acknowledge, clear _AND_ disable the interrupt.
	 */

	printk (KERN_INFO "do_twl4030 irq\n") ;

	desc->chip->ack(irq);

	printk (KERN_INFO "desc_disable depth => %d\n", desc->disable_depth) ;

	if (!desc->disable_depth) {
		kstat_cpu(cpu).irqs[irq]++;

		//desc->status |= IRQ_INPROGRESS;
		printk ("thread->state=> %x:%d\n", thread, thread->state) ;
		if (thread && thread->state != TASK_RUNNING) {
			printk (KERN_INFO "Calling twl_module_irq\n") ;
			wake_up_process(thread);
		}
	}
}

/* attach a client to the adapter */
static int twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid)
{
	int err = 0;
	struct twl4030_client *client;

	FN_IN;
	if (unlikely(sid >= TWL4030_NUM_SLAVES)) {
		printk(KERN_ERR "TWL4030: sid[%d] >MOD_LAST[%d]\n", sid,
		       TWL4030_NUM_SLAVES);
		FN_OUT(EPERM);
		return -EPERM;
	}

	/* Check basic functionality */
	if (!(err = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
					    I2C_FUNC_SMBUS_WRITE_BYTE))) {
		printk(KERN_WARNING
		       "TWL4030: SlaveID=%d functionality check failed\n", sid);
		FN_OUT(err);
		return err;
	}
	client = &(twl4030_modules[sid]);
	if (unlikely(client->inuse)) {
		printk(KERN_ERR "TWL4030: Client is already in Use.....\n");
		printk("%s[ID=0x%x] NOT attached to I2c Adapter %s\n",
		       client->client_name, client->address, adapter->name);
		FN_OUT(EPERM);
		return -EPERM;
	}

	memset(&(client->client), 0, sizeof(struct i2c_client));

	client->client.addr = client->address;
	client->client.adapter = adapter;
	client->client.driver = &twl4030_driver;
	if ((adapter->flags & I2C_FUNC_HIGH_SPEED) == I2C_FUNC_HIGH_SPEED) {
		client->client.flags = I2C_M_HS;	/* We are HS capable */
	} 
	memcpy(&(client->client.name), client->client_name,
	       sizeof(TWL_CLIENT_STRING) + 1);
	client->client.id = twl4030_id++;
//XXX	client->client.data = (void *)client;
	if ((err = i2c_attach_client(&(client->client)))) {
		printk(KERN_WARNING
		       "TWL4030: Couldn't attach Slave %s on Adapter %s[%d][%x]\n",
		       client->client_name, adapter->name, err, err);
	} else {
		D1( "TWL4030: %s[ID=0x%x] attached to I2c Adapter %s\n",
		       client->client_name, client->address, adapter->name);
		client->inuse = TWL_CLIENT_USED;
		init_MUTEX(&client->xfer_lock);
	}
	FN_OUT(err);
	return err;
}

/* adapter callback */
static int twl4030_attach_adapter(struct i2c_adapter *adapter)
{
	int i;
	int ret = 0;
	static int twl_i2c_adapter = 0;
	FN_IN;

	printk (KERN_INFO "twl attach adapter\n") ;

	for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
		/* Check if I need to hook on to this adapter or not */
		
		if (twl4030_modules[i].adapter_index == twl_i2c_adapter) {
			 printk (KERN_INFO "Detect CLient\n") ;
			if ((ret = twl4030_detect_client(adapter, i))) {
				  printk (KERN_INFO "Free Client: %d\n", i) ;
				goto free_client;
			}
		}
	}
	twl_i2c_adapter++;

	/* Check if the PIH module is initialized, if yes, then init
	 * the T2 Interrupt subsystem
	 */
	printk (KERN_INFO "inuse: %d, %d\n", \
		twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse, twl_irq_used);

	if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse ==
	     TWL_CLIENT_USED) && (twl_irq_used != USED)) {
		printk (KERN_INFO "twl_init_irq") ;
		twl_init_irq();
		twl_irq_used = USED;
	}
	FN_OUT(0);
	return 0;
      free_client:
	printk(KERN_ERR
	       "TWL4030: TWL_CLIENT(Idx=%d] REGISTRATION FAILED=%d[0x%x]\n", i,
	       ret, ret);
	/* ignore current slave..it never got registered */
	i--;
	while (i >= 0) {
		/* now remove all those from the current adapter... */
		if (twl4030_modules[i].adapter_index == twl_i2c_adapter) {
			(void)
			    twl4030_detach_client(&(twl4030_modules[i].client));
		}
		i--;
	}
	FN_OUT(ret);
	return ret;
}

/* adapter's callback */
static int twl4030_detach_client(struct i2c_client *iclient)
{
	int err;
	//XXX struct twl4030_client *client = (struct twl4030_client *)iclient->data;
	FN_IN;
	if ((err = i2c_detach_client(iclient))) {
		printk(KERN_ERR
		       "TWL4030: Client deregistration failed, client not detached.\n");
		FN_OUT(err);
		return err;
	}

	/* Free 'em up */
	//XXX client->inuse = TWL_CLIENT_FREE;
	FN_OUT(0);

	return 0;
}

struct task_struct *
start_twl4030_irq_thread(int irq)
{
	struct task_struct *thread;

	thread = kthread_create(twl4030_irq_thread, (void *) irq, 
		"twl4030 irq %d", irq);
	if (!thread) {
		printk(KERN_ERR 
			"%s: could not create twl4030 irq %d thread!\n", 
			__FUNCTION__, irq);
	}

	return thread;
}

static void twl_init_irq(void)
{
	int i = 0;
	int res = 0;
	int line = 0;
	FN_IN;
#if 0
	/*
	 * PARANOIA:
	 * Before we enable The module, check if the interrupt module has been initialized successfully
	 * Already checked - but *if* this going to be used from elsewhere...
	 */
	if (unlikely
	    (twl4030_modules[twl4030_map[TWL4030_MODULE_PIH].sid].inuse !=
	     TWL_CLIENT_USED)) {
		printk(KERN_ERR
		       "TWL4030: TWL4030-Interrupt Module not registered\n");
		/* Dont care abt deletion result!!-This should not happen at all */
		BUG();
		return;
	}
#endif
#if (TWL4030_IRQNUM != INT_SYS)
	if (omap_request_gpio(TWL4030_GPIO) != 0) {
		printk(KERN_ERR "TWL4030: Could not reserve GPIO!\n");
		/* Dont care abt deletion result!! */
		FN_OUT(-1);
		return;
	};
	omap_set_gpio_direction(TWL4030_GPIO, OMAP24XX_DIR_INPUT);
	omap_set_gpio_edge_ctrl(TWL4030_GPIO, OMAP_GPIO_FALLING_EDGE);
#endif
	/* We end up with interrupts from other modules before
	 * they get a chance to handle them...
	 */
	/* HACK ALERT - No Body to handle power ISR yet... */
	/* POWER HACK (BEGIN) */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);	/* PWR_ISR1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);	/* PWR_ISR2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	/* MASK PWR -we will need this */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);	/* PWR_IMR1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);	/* PWR_IMR2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	/* Clear off any other pending interrupts on power */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);	/* PWR_ISR1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);	/* PWR_ISR2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	/* POWER HACK (END) */
	/* Slave address 0x4A */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);	/* BCIIMR1_1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);	/* BCIIMR1_2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);	/* BCIIMR2_1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);	/* BCIIMR2_2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	/* MAD C */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);	/* MADC_IMR1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);	/* MADC_IMR2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	/* key Pad */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x12));	/* KEYPAD - IMR1 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x14));	/* KEYPAD - IMR2 */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}

	/* Slave address 0x49 */
	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1C));	/* GPIO_IMR1A */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}

	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1D));	/* GPIO_IMR2A */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}

	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1E));	/* GPIO_IMR3A */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x22));	/* GPIO_IMR1B */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x23));	/* GPIO_IMR2B */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}
	res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x24));	/* GPIO_IMR3B */
	if (res < 0) {
		line = __LINE__;
		goto irq_exit_path;
	}


	/* install an irq handler for each of the PIH modules */
	for (i = IH_TWL4030_BASE; i <= IH_TWL4030_END; i++) {
			set_irq_chip(i, &twl4030_irq_chip);
			set_irq_handler(i, do_twl4030_module_irq);
			set_irq_flags(i, IRQF_VALID);
	}

	/* install an irq handler to demultiplex the TWL4030 interrupt */
	set_irq_data(TWL4030_IRQNUM, start_twl4030_irq_thread(TWL4030_IRQNUM));
	set_irq_chained_handler(TWL4030_IRQNUM, do_twl4030_irq);
	
	power_companion_init();  /* finish power and clock init */

      irq_exit_path:
	if (res) {
		printk(KERN_ERR
		       "TWL4030: Unable to register interrupt subsystem[%d][%d]\n",
		       res, line);
	}
	FN_OUT(res);
}

static int __init twl4030_init(void)
{
	int res;
	FN_IN;

	if ((res = i2c_add_driver(&twl4030_driver))) {
		printk(KERN_ERR
		       "TWL4030: Driver registration failed, module not inserted.\n");
		FN_OUT(res);
		return res;
	}
#if (TWL4030_LOG_LEVEL >= 1)
	{
		/* debug dump */
		int mod = 0;
		for (mod = 0; mod <= TWL4030_MODULE_LAST; mod++) {
			u8 sid = twl4030_map[mod].sid;
			u8 sadd = twl4030_modules[sid].address;
			printk
			    ("W8 - mod=%d[0x%x], sid=%d[0x%x] sad=%d[0x%x], modRegBaseAdd=%d[0x%x] \n",
			     mod, mod, sid, sid, sadd, sadd,
			     twl4030_map[mod].base, twl4030_map[mod].base);
		}
	}
#endif

#if CONFIG_I2C_TWL4030_DBG_SYSFS
	{
		int ret = 0;
		/* A dummy device */
		ret = platform_device_register(&twl4030_debug_dev);
		if (ret != 0) {
			printk(KERN_ERR "Platform dev_register failed =%d\n", ret);
			ret = -ENODEV;
		} else {
			TWL_SYS_DEV();
		}
	}
#endif

	printk(KERN_INFO "TWL4030: Driver registration complete.\n");
	FN_OUT(res);
	return res;
}

static void __exit twl4030_exit(void)
{
	FN_IN;
	if (i2c_del_driver(&twl4030_driver)) {
		printk(KERN_ERR
		       "TWL4030: Driver remove failed, module not removed.\n");
	}
	twl_irq_used = FREE;
#if (TWL4030_IRQNUM != INT_SYS)
	omap_free_gpio(TWL4030_GPIO);
#endif

	FN_OUT(0);
}

subsys_initcall(twl4030_init);
module_exit(twl4030_exit);

EXPORT_SYMBOL(twl4030_i2c_write_u8);
EXPORT_SYMBOL(twl4030_i2c_read_u8);
EXPORT_SYMBOL(twl4030_i2c_read);
EXPORT_SYMBOL(twl4030_i2c_write);

MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("I2C Core interface for TWL4030");
MODULE_LICENSE("GPL");

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux