All of lore.kernel.org
 help / color / mirror / Atom feed
* irqdesc porting help
@ 2007-02-15  6:31 Maximus
  2007-02-15 10:33 ` Paul Mundt
  0 siblings, 1 reply; 10+ messages in thread
From: Maximus @ 2007-02-15  6:31 UTC (permalink / raw)
  To: linux-kernel

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.


Could anyone help me on this.

Regards,
Jo

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

* Re: irqdesc porting help
  2007-02-15  6:31 irqdesc porting help Maximus
@ 2007-02-15 10:33 ` Paul Mundt
  2007-02-15 10:45   ` Russell King
  2007-02-20  7:03   ` Maximus
  0 siblings, 2 replies; 10+ messages in thread
From: Paul Mundt @ 2007-02-15 10:33 UTC (permalink / raw)
  To: Maximus; +Cc: linux-kernel

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.

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

* Re: irqdesc porting help
  2007-02-15 10:33 ` Paul Mundt
@ 2007-02-15 10:45   ` Russell King
  2007-02-15 13:11     ` Maximus
  2007-02-20  7:03   ` Maximus
  1 sibling, 1 reply; 10+ messages in thread
From: Russell King @ 2007-02-15 10:45 UTC (permalink / raw)
  To: Paul Mundt, Maximus, linux-kernel

On Thu, Feb 15, 2007 at 07:33:47PM +0900, Paul Mundt 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.

It should be asked - why are drivers poking about in the irqdesc
structure?

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

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

* Re: irqdesc porting help
  2007-02-15 10:45   ` Russell King
@ 2007-02-15 13:11     ` Maximus
  2007-02-15 13:16       ` Russell King
  2007-02-15 13:16       ` Arjan van de Ven
  0 siblings, 2 replies; 10+ messages in thread
From: Maximus @ 2007-02-15 13:11 UTC (permalink / raw)
  To: Paul Mundt, linux-kernel

Hi,
   My drivers in 2.6.14 use statements like
             desc->triggered = 1;
   And desc also points to some members of irqdesc which arent in
2.6.19 but in 2.6.14.

   Im a newbie, What changes am i supposed to make to make it work in 2.6.19.
   Im not sure what changes are exactly needed.


  Please Advice,

  Regards,
   Jo



On 2/15/07, Russell King <rmk+lkml@arm.linux.org.uk> wrote:
> On Thu, Feb 15, 2007 at 07:33:47PM +0900, Paul Mundt 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.
>
> It should be asked - why are drivers poking about in the irqdesc
> structure?
>
> --
> Russell King
>  Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
>  maintainer of:
>

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

* Re: irqdesc porting help
  2007-02-15 13:11     ` Maximus
@ 2007-02-15 13:16       ` Russell King
  2007-02-15 13:16       ` Arjan van de Ven
  1 sibling, 0 replies; 10+ messages in thread
From: Russell King @ 2007-02-15 13:16 UTC (permalink / raw)
  To: Maximus; +Cc: Paul Mundt, linux-kernel

On Thu, Feb 15, 2007 at 06:41:25PM +0530, Maximus wrote:
> Hi,
>   My drivers in 2.6.14 use statements like
>             desc->triggered = 1;
>   And desc also points to some members of irqdesc which arent in
> 2.6.19 but in 2.6.14.

But why do you have code which accesses these members?  Can you show
your code?

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

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

* Re: irqdesc porting help
  2007-02-15 13:11     ` Maximus
  2007-02-15 13:16       ` Russell King
@ 2007-02-15 13:16       ` Arjan van de Ven
  1 sibling, 0 replies; 10+ messages in thread
From: Arjan van de Ven @ 2007-02-15 13:16 UTC (permalink / raw)
  To: Maximus; +Cc: Paul Mundt, linux-kernel

On Thu, 2007-02-15 at 18:41 +0530, Maximus wrote:
> Hi,
>    My drivers in 2.6.14 use statements like
>              desc->triggered = 1;
>    And desc also points to some members of irqdesc which arent in
> 2.6.19 but in 2.6.14.
> 
>    Im a newbie, What changes am i supposed to make to make it work in 2.6.19.
>    Im not sure what changes are exactly needed.
> 


can you just post your driver so that the people here see what you are
actually doing ?



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

* Re: irqdesc porting help
  2007-02-15 10:33 ` Paul Mundt
  2007-02-15 10:45   ` Russell King
@ 2007-02-20  7:03   ` Maximus
  2007-02-20 10:54     ` Komal Shah
  2007-02-20 11:48     ` Thomas Gleixner
  1 sibling, 2 replies; 10+ messages in thread
From: Maximus @ 2007-02-20  7:03 UTC (permalink / raw)
  To: Paul Mundt, linux-kernel, arjan

[-- Attachment #1: Type: text/plain, Size: 1143 bytes --]

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 <lethal@linux-sh.org> 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.
>

[-- Attachment #2: twl4030_core.c --]
[-- Type: text/x-csrc, Size: 36609 bytes --]

/*
 * 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 <kai.svahn@nokia.com>
 *
 * 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");

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

* Re: irqdesc porting help
  2007-02-20  7:03   ` Maximus
@ 2007-02-20 10:54     ` Komal Shah
  2007-02-20 10:58       ` Komal Shah
  2007-02-20 11:48     ` Thomas Gleixner
  1 sibling, 1 reply; 10+ messages in thread
From: Komal Shah @ 2007-02-20 10:54 UTC (permalink / raw)
  To: Maximus; +Cc: Paul Mundt, linux-kernel, arjan

Maximus,

On 2/20/07, Maximus <john.maximus@gmail.com> wrote:
> Hi,
>   Sorry for the late response, attached is the code im trying to port
> to linux - 2.6.20.
>
>

Have you checked http://source.mvista.com/git linux-omap-2.6 git tree.
Syed Khasim has already submitted this OMAP2430 TWL4030 chip core
driver there, which is already synced with 2.6.20.

-- 
---Komal Shah
http://komalshah.blogspot.com

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

* Re: irqdesc porting help
  2007-02-20 10:54     ` Komal Shah
@ 2007-02-20 10:58       ` Komal Shah
  0 siblings, 0 replies; 10+ messages in thread
From: Komal Shah @ 2007-02-20 10:58 UTC (permalink / raw)
  To: Maximus; +Cc: Paul Mundt, linux-kernel, arjan

On 2/20/07, Komal Shah <komal.shah802003@gmail.com> wrote:
> Maximus,
>
> On 2/20/07, Maximus <john.maximus@gmail.com> wrote:
> > Hi,
> >   Sorry for the late response, attached is the code im trying to port
> > to linux - 2.6.20.
> >
> >
>
> Have you checked http://source.mvista.com/git linux-omap-2.6 git tree.
> Syed Khasim has already submitted this OMAP2430 TWL4030 chip core
> driver there, which is already synced with 2.6.20.
>

I just checked that code, and there is a line like:

393 /*
394 * Earlier this was desc->triggered = 1;
395 */
396 desc->status = IRQ_INPROGRESS;

So, I hope this helps, but still need to check its correctness.

-- 
---Komal Shah
http://komalshah.blogspot.com

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

* Re: irqdesc porting help
  2007-02-20  7:03   ` Maximus
  2007-02-20 10:54     ` Komal Shah
@ 2007-02-20 11:48     ` Thomas Gleixner
  1 sibling, 0 replies; 10+ messages in thread
From: Thomas Gleixner @ 2007-02-20 11:48 UTC (permalink / raw)
  To: Maximus; +Cc: Paul Mundt, linux-kernel, arjan

On Tue, 2007-02-20 at 12:33 +0530, Maximus wrote:
> Hi,
>   Sorry for the late response, attached is the code im trying to port
> to linux - 2.6.20.

Why does this need to use a kernel thread in the first place ? Usually
chained handlers demultiplex the primary interrupt and invoke the
demultiplexed interrupts.

There are tons of working examples in arch/arm/mach-xxxx

	tglx



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

end of thread, other threads:[~2007-02-20 11:43 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-15  6:31 irqdesc porting help Maximus
2007-02-15 10:33 ` Paul Mundt
2007-02-15 10:45   ` Russell King
2007-02-15 13:11     ` Maximus
2007-02-15 13:16       ` Russell King
2007-02-15 13:16       ` Arjan van de Ven
2007-02-20  7:03   ` Maximus
2007-02-20 10:54     ` Komal Shah
2007-02-20 10:58       ` Komal Shah
2007-02-20 11:48     ` Thomas Gleixner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.