Re: [PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-02-13 Thread Peter Ujfalusi
Hi Jon,

On 02/12/2013 05:15 PM, Jon Hunter wrote:
 
 On 02/12/2013 01:26 AM, Peter Ujfalusi wrote:
 On 02/11/2013 09:22 PM, Jon Hunter wrote:
 Good point. I just noticed that none of my omap2+ board were booting and
 on omap3/4 I was the panic in the twl code. I can't say that I checked
 the panic on omap2, so may be that was another problem?

 Do you have insights on the code path leading to a crash on OMAP3/4? I have
 been running this code on several boards (BeagleBoard, Zoom2, PandaBoard,
 Blaze) and have not seen a crash.
 
 Here is the panic log ...

Thanks.

 
 [2.286132] Unable to handle kernel NULL pointer dereference at virtual 
 address 
 [2.294738] pgd = c0004000
 [2.297576] [] *pgd=
 [2.301361] Internal error: Oops: 5 [#1] SMP ARM
 [2.306243] Modules linked in:
 [2.309448] CPU: 0Not tainted  (3.8.0-rc6-next-20130207-00016-g735c237 
 #35)
 [2.317169] PC is at twl_i2c_read+0x3c/0xec
 [2.321563] LR is at twl_i2c_read+0x1c/0xec
 [2.325988] pc : [c0333950]lr : [c0333930]psr: 8153
 [2.325988] sp : c702fed0  ip :   fp : 
 [2.338043] r10: c702e000  r9 : c06e84e8  r8 : c06e51c8
 [2.343536] r7 : 0001  r6 : 0006  r5 : c702fef6  r4 : 0004
 [2.350402] r3 : c129508c  r2 : 0006  r1 : c702fef6  r0 : 000e
 [2.357269] Flags: Nzcv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment 
 kernel
 [2.365051] Control: 10c5387d  Table: 80004019  DAC: 0017
 [2.371093] Process swapper/0 (pid: 1, stack limit = 0xc702e240)
 [2.377410] Stack: (0xc702fed0 to 0xc703)
 [2.382019] fec0: c0d42180 c0d429d0 
 c70a7640 c07354c4
 [2.390624] fee0: 0001 c0719798 c0d42180 c06f2cc0 c04e76cc c06ee1ac 
  c07354c4
 [2.399230] ff00: 0007 c06f2d64 0017 c06fb308  c06f07a4 
 c0cb8580 c06edee0
 [2.407836] ff20: c06eded4 c06e8504 c0d42180 c0008768 009e c00611b4 
 0001 
 [2.416442] ff40: c061994c c06b7548 0007 0007  c07354c4 
 0007 c0719798
 [2.425048] ff60: c0d42180 c06e51c8 c07197a0 009e  c06e590c 
 0007 0007
 [2.433654] ff80: c06e51c8   c04d26ec   
  
 [2.442260] ffa0:  c04d26f4  c00137b0   
  
 [2.450866] ffc0:       
  
 [2.459472] ffe0:     0013  
 80fb6c10 71bbcd20
 [2.468078] [c0333950] (twl_i2c_read+0x3c/0xec) from [c06f2cc0] 
 (omap3_twl_set_sr_bit+0x3c/0xb4)
 [2.477722] [c06f2cc0] (omap3_twl_set_sr_bit+0x3c/0xb4) from 
 [c06f2d64] (omap3_twl_init+0x2c/0x70)
 [2.487518] [c06f2d64] (omap3_twl_init+0x2c/0x70) from [c06fb308] 
 (omap_pmic_late_init+0x18/0x24)
 [2.497222] [c06fb308] (omap_pmic_late_init+0x18/0x24) from [c06f07a4] 
 (omap2_common_pm_late_init+0x18/0xd0)
 [2.507934] [c06f07a4] (omap2_common_pm_late_init+0x18/0xd0) from 
 [c06edee0] (omap3_init_late+0xc/0x18)
 [2.518188] [c06edee0] (omap3_init_late+0xc/0x18) from [c06e8504] 
 (init_machine_late+0x1c/0x28)
 [2.527740] [c06e8504] (init_machine_late+0x1c/0x28) from [c0008768] 
 (do_one_initcall+0x100/0x16c)
 [2.537536] [c0008768] (do_one_initcall+0x100/0x16c) from [c06e590c] 
 (kernel_init_freeable+0xfc/0x1c8)
 [2.547698] [c06e590c] (kernel_init_freeable+0xfc/0x1c8) from 
 [c04d26f4] (kernel_init+0x8/0xe4)
 [2.557250] [c04d26f4] (kernel_init+0x8/0xe4) from [c00137b0] 
 (ret_from_fork+0x14/0x24)

This is exactly the sort of thing which should not ever existed in the first
place...
The code in omap_twl.c, especially the omap3_twl_set_sr_bit() function is
executed in .init_late of the board. If the twl stack is not up by then we are
going to have issues.
Right now I don't see how to solve this (the call chain is related to
smartreflex) but IMHO we should not have these 'random' twl_write calls spread
across the kernel without integrating them to the twl stack in a proper
manner. What I mean is that we should only have twl_* calls from drivers,
which has been created by the twl-core MFD core.

-- 
Péter
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-02-12 Thread Jon Hunter

On 02/12/2013 01:26 AM, Peter Ujfalusi wrote:
 On 02/11/2013 09:22 PM, Jon Hunter wrote:
 Good point. I just noticed that none of my omap2+ board were booting and
 on omap3/4 I was the panic in the twl code. I can't say that I checked
 the panic on omap2, so may be that was another problem?
 
 Do you have insights on the code path leading to a crash on OMAP3/4? I have
 been running this code on several boards (BeagleBoard, Zoom2, PandaBoard,
 Blaze) and have not seen a crash.

Here is the panic log ...

[2.286132] Unable to handle kernel NULL pointer dereference at virtual 
address 
[2.294738] pgd = c0004000
[2.297576] [] *pgd=
[2.301361] Internal error: Oops: 5 [#1] SMP ARM
[2.306243] Modules linked in:
[2.309448] CPU: 0Not tainted  (3.8.0-rc6-next-20130207-00016-g735c237 
#35)
[2.317169] PC is at twl_i2c_read+0x3c/0xec
[2.321563] LR is at twl_i2c_read+0x1c/0xec
[2.325988] pc : [c0333950]lr : [c0333930]psr: 8153
[2.325988] sp : c702fed0  ip :   fp : 
[2.338043] r10: c702e000  r9 : c06e84e8  r8 : c06e51c8
[2.343536] r7 : 0001  r6 : 0006  r5 : c702fef6  r4 : 0004
[2.350402] r3 : c129508c  r2 : 0006  r1 : c702fef6  r0 : 000e
[2.357269] Flags: Nzcv  IRQs on  FIQs off  Mode SVC_32  ISA ARM  Segment 
kernel
[2.365051] Control: 10c5387d  Table: 80004019  DAC: 0017
[2.371093] Process swapper/0 (pid: 1, stack limit = 0xc702e240)
[2.377410] Stack: (0xc702fed0 to 0xc703)
[2.382019] fec0: c0d42180 c0d429d0 
c70a7640 c07354c4
[2.390624] fee0: 0001 c0719798 c0d42180 c06f2cc0 c04e76cc c06ee1ac 
 c07354c4
[2.399230] ff00: 0007 c06f2d64 0017 c06fb308  c06f07a4 
c0cb8580 c06edee0
[2.407836] ff20: c06eded4 c06e8504 c0d42180 c0008768 009e c00611b4 
0001 
[2.416442] ff40: c061994c c06b7548 0007 0007  c07354c4 
0007 c0719798
[2.425048] ff60: c0d42180 c06e51c8 c07197a0 009e  c06e590c 
0007 0007
[2.433654] ff80: c06e51c8   c04d26ec   
 
[2.442260] ffa0:  c04d26f4  c00137b0   
 
[2.450866] ffc0:       
 
[2.459472] ffe0:     0013  
80fb6c10 71bbcd20
[2.468078] [c0333950] (twl_i2c_read+0x3c/0xec) from [c06f2cc0] 
(omap3_twl_set_sr_bit+0x3c/0xb4)
[2.477722] [c06f2cc0] (omap3_twl_set_sr_bit+0x3c/0xb4) from [c06f2d64] 
(omap3_twl_init+0x2c/0x70)
[2.487518] [c06f2d64] (omap3_twl_init+0x2c/0x70) from [c06fb308] 
(omap_pmic_late_init+0x18/0x24)
[2.497222] [c06fb308] (omap_pmic_late_init+0x18/0x24) from [c06f07a4] 
(omap2_common_pm_late_init+0x18/0xd0)
[2.507934] [c06f07a4] (omap2_common_pm_late_init+0x18/0xd0) from 
[c06edee0] (omap3_init_late+0xc/0x18)
[2.518188] [c06edee0] (omap3_init_late+0xc/0x18) from [c06e8504] 
(init_machine_late+0x1c/0x28)
[2.527740] [c06e8504] (init_machine_late+0x1c/0x28) from [c0008768] 
(do_one_initcall+0x100/0x16c)
[2.537536] [c0008768] (do_one_initcall+0x100/0x16c) from [c06e590c] 
(kernel_init_freeable+0xfc/0x1c8)
[2.547698] [c06e590c] (kernel_init_freeable+0xfc/0x1c8) from [c04d26f4] 
(kernel_init+0x8/0xe4)
[2.557250] [c04d26f4] (kernel_init+0x8/0xe4) from [c00137b0] 
(ret_from_fork+0x14/0x24)

 But the fix is valid.
 
Thanks. I saw this on linux-next earlier this week, but now I am not seeing it 
and the fix
I posted is not there. So I am not sure what changed to cause this to occur 
earlier this
week but the problem appears to be gone again. However, at least the fix will 
prevent such
panics if someone is calling twl_i2c_read/write too early.

Cheers
Jon
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-02-11 Thread Jon Hunter

On 02/08/2013 11:50 PM, Peter Ujfalusi wrote:
 On 02/08/2013 07:56 PM, Jon Hunter wrote:
  /**
   * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
   * @mod_no: module number
 @@ -322,16 +323,17 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, 
 unsigned num_bytes)
 pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
 return -EPERM;
 }
 -   if (unlikely(!inuse)) {
 +   if (unlikely(!twl_priv-ready)) {

 This is causing the kernel to panic on all my omap2 boards when booting 
 linux-next
 because twl_priv is not initialised yet.
 
 Good catch.
 I just wonder from where the twl_* call is coming on OMAP2. AFAIK the twl code
 is for OMAP3/4, for OMAP2 Menelaus is the one which is used.
 I'm currently working on to remove all those twl_* calls from random places in
 the kernel so we will only access twl via the MFD stack.

Good point. I just noticed that none of my omap2+ board were booting and
on omap3/4 I was the panic in the twl code. I can't say that I checked
the panic on omap2, so may be that was another problem?

I will update the changelog and re-send the patch.

Cheers
Jon
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-02-11 Thread Peter Ujfalusi
On 02/11/2013 09:22 PM, Jon Hunter wrote:
 Good point. I just noticed that none of my omap2+ board were booting and
 on omap3/4 I was the panic in the twl code. I can't say that I checked
 the panic on omap2, so may be that was another problem?

Do you have insights on the code path leading to a crash on OMAP3/4? I have
been running this code on several boards (BeagleBoard, Zoom2, PandaBoard,
Blaze) and have not seen a crash.
But the fix is valid.

-- 
Péter
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-02-08 Thread Jon Hunter

On 01/16/2013 07:53 AM, Peter Ujfalusi wrote:
 Gather the global variables under a single structure and allocate it with
 devm_kzalloc(). It is easier to see them and if in the future we try to add
 support for multiple instance of twl in the system it is going to be much
 simpler.
 
 Signed-off-by: Peter Ujfalusi peter.ujfal...@ti.com
 ---
  drivers/mfd/twl-core.c | 104 
 +++--
  1 file changed, 57 insertions(+), 47 deletions(-)
 
 diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
 index 1827088..e2895a4 100644
 --- a/drivers/mfd/twl-core.c
 +++ b/drivers/mfd/twl-core.c
 @@ -141,33 +141,28 @@
  
  /*--*/
  
 -/* is driver active, bound to a chip? */
 -static bool inuse;
 -
 -/* TWL IDCODE Register value */
 -static u32 twl_idcode;
 -
 -static unsigned int twl_id;
 -unsigned int twl_rev(void)
 -{
 - return twl_id;
 -}
 -EXPORT_SYMBOL(twl_rev);
 -
  /* Structure for each TWL4030/TWL6030 Slave */
  struct twl_client {
   struct i2c_client *client;
   struct regmap *regmap;
  };
  
 -static struct twl_client *twl_modules;
 -
  /* mapping the module id to slave id and base address */
  struct twl_mapping {
   unsigned char sid;  /* Slave ID */
   unsigned char base; /* base address */
  };
 -static struct twl_mapping *twl_map;
 +
 +struct twl_private {
 + bool ready; /* The core driver is ready to be used */
 + u32 twl_idcode; /* TWL IDCODE Register value */
 + unsigned int twl_id;
 +
 + struct twl_mapping *twl_map;
 + struct twl_client *twl_modules;
 +};
 +
 +static struct twl_private *twl_priv;
  
  static struct twl_mapping twl4030_map[] = {
   /*
 @@ -300,6 +295,12 @@ static inline int twl_get_last_module(void)
  
  /* Exported Functions */
  
 +unsigned int twl_rev(void)
 +{
 + return twl_priv ? twl_priv-twl_id : 0;
 +}
 +EXPORT_SYMBOL(twl_rev);
 +
  /**
   * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
   * @mod_no: module number
 @@ -322,16 +323,17 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, 
 unsigned num_bytes)
   pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
   return -EPERM;
   }
 - if (unlikely(!inuse)) {
 + if (unlikely(!twl_priv-ready)) {

This is causing the kernel to panic on all my omap2 boards when booting 
linux-next
because twl_priv is not initialised yet.

   pr_err(%s: not initialized\n, DRIVER_NAME);
   return -EPERM;
   }
  
 - sid = twl_map[mod_no].sid;
 - twl = twl_modules[sid];
 + sid = twl_priv-twl_map[mod_no].sid;
 + twl = twl_priv-twl_modules[sid];
  
 - ret = regmap_bulk_write(twl-regmap, twl_map[mod_no].base + reg,
 - value, num_bytes);
 + ret = regmap_bulk_write(twl-regmap,
 + twl_priv-twl_map[mod_no].base + reg, value,
 + num_bytes);
  
   if (ret)
   pr_err(%s: Write failed (mod %d, reg 0x%02x count %d)\n,
 @@ -360,16 +362,17 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned 
 num_bytes)
   pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
   return -EPERM;
   }
 - if (unlikely(!inuse)) {
 + if (unlikely(!twl_priv-ready)) {

Same problem here. 

Here is a fix ...

From 141fcbbdee6bdc14d5a444ff20fad6b3440215dc Mon Sep 17 00:00:00 2001
From: Jon Hunter jon-hun...@ti.com
Date: Fri, 8 Feb 2013 12:42:20 -0600
Subject: [PATCH] ARM: OMAP2+: Fix kernel panic on boot

Commit 8a6aaa3 (mfd: twl-core: Collect global variables behind one
private structure (global)) removed the variable inuse that is used
to determine if the device has been initialised and now use the
twl_priv structure instead. This is causing the kernel to panic on all
OMAP2+ devices, because we try to access the twl_priv-ready member
before checking if twl_priv is initialised. Fix this and move this test
to the beginning of the twl_i2c_read/write function because
twl_get_last_module() also uses the twl_priv structure.

Signed-off-by: Jon Hunter jon-hun...@ti.com
---
 drivers/mfd/twl-core.c |   16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 557f9ee..89ab4d9 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -316,12 +316,12 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned 
num_bytes)
int sid;
struct twl_client *twl;
 
-   if (unlikely(mod_no = twl_get_last_module())) {
-   pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
+   if (unlikely(!twl_priv || !twl_priv-ready)) {
+   pr_err(%s: not initialized\n, DRIVER_NAME);
return -EPERM;
}
-   if (unlikely(!twl_priv-ready)) {
-   pr_err(%s: not initialized\n, DRIVER_NAME);
+   if (unlikely(mod_no = 

Re: [PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-02-08 Thread Peter Ujfalusi
On 02/08/2013 07:56 PM, Jon Hunter wrote:
  /**
   * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
   * @mod_no: module number
 @@ -322,16 +323,17 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, 
 unsigned num_bytes)
  pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
  return -EPERM;
  }
 -if (unlikely(!inuse)) {
 +if (unlikely(!twl_priv-ready)) {
 
 This is causing the kernel to panic on all my omap2 boards when booting 
 linux-next
 because twl_priv is not initialised yet.

Good catch.
I just wonder from where the twl_* call is coming on OMAP2. AFAIK the twl code
is for OMAP3/4, for OMAP2 Menelaus is the one which is used.
I'm currently working on to remove all those twl_* calls from random places in
the kernel so we will only access twl via the MFD stack.

 
  pr_err(%s: not initialized\n, DRIVER_NAME);
  return -EPERM;
  }
  
 -sid = twl_map[mod_no].sid;
 -twl = twl_modules[sid];
 +sid = twl_priv-twl_map[mod_no].sid;
 +twl = twl_priv-twl_modules[sid];
  
 -ret = regmap_bulk_write(twl-regmap, twl_map[mod_no].base + reg,
 -value, num_bytes);
 +ret = regmap_bulk_write(twl-regmap,
 +twl_priv-twl_map[mod_no].base + reg, value,
 +num_bytes);
  
  if (ret)
  pr_err(%s: Write failed (mod %d, reg 0x%02x count %d)\n,
 @@ -360,16 +362,17 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, 
 unsigned num_bytes)
  pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
  return -EPERM;
  }
 -if (unlikely(!inuse)) {
 +if (unlikely(!twl_priv-ready)) {
 
 Same problem here. 
 
 Here is a fix ...
 
 From 141fcbbdee6bdc14d5a444ff20fad6b3440215dc Mon Sep 17 00:00:00 2001
 From: Jon Hunter jon-hun...@ti.com
 Date: Fri, 8 Feb 2013 12:42:20 -0600
 Subject: [PATCH] ARM: OMAP2+: Fix kernel panic on boot
 
 Commit 8a6aaa3 (mfd: twl-core: Collect global variables behind one
 private structure (global)) removed the variable inuse that is used
 to determine if the device has been initialised and now use the
 twl_priv structure instead. This is causing the kernel to panic on all
 OMAP2+ devices, because we try to access the twl_priv-ready member
 before checking if twl_priv is initialised. Fix this and move this test
 to the beginning of the twl_i2c_read/write function because
 twl_get_last_module() also uses the twl_priv structure.
 
 Signed-off-by: Jon Hunter jon-hun...@ti.com

Acked-by: Peter Ujfalusi peter.ujfal...@ti.com

 ---
  drivers/mfd/twl-core.c |   16 
  1 file changed, 8 insertions(+), 8 deletions(-)
 
 diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
 index 557f9ee..89ab4d9 100644
 --- a/drivers/mfd/twl-core.c
 +++ b/drivers/mfd/twl-core.c
 @@ -316,12 +316,12 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, 
 unsigned num_bytes)
   int sid;
   struct twl_client *twl;
  
 - if (unlikely(mod_no = twl_get_last_module())) {
 - pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
 + if (unlikely(!twl_priv || !twl_priv-ready)) {
 + pr_err(%s: not initialized\n, DRIVER_NAME);
   return -EPERM;
   }
 - if (unlikely(!twl_priv-ready)) {
 - pr_err(%s: not initialized\n, DRIVER_NAME);
 + if (unlikely(mod_no = twl_get_last_module())) {
 + pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
   return -EPERM;
   }
  
 @@ -355,12 +355,12 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned 
 num_bytes)
   int sid;
   struct twl_client *twl;
  
 - if (unlikely(mod_no = twl_get_last_module())) {
 - pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
 + if (unlikely(!twl_priv || !twl_priv-ready)) {
 + pr_err(%s: not initialized\n, DRIVER_NAME);
   return -EPERM;
   }
 - if (unlikely(!twl_priv-ready)) {
 - pr_err(%s: not initialized\n, DRIVER_NAME);
 + if (unlikely(mod_no = twl_get_last_module())) {
 + pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
   return -EPERM;
   }
  
 


-- 
Péter
--
To unsubscribe from this list: send the line unsubscribe linux-omap in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 09/11] mfd: twl-core: Collect global variables behind one private structure (global)

2013-01-16 Thread Peter Ujfalusi
Gather the global variables under a single structure and allocate it with
devm_kzalloc(). It is easier to see them and if in the future we try to add
support for multiple instance of twl in the system it is going to be much
simpler.

Signed-off-by: Peter Ujfalusi peter.ujfal...@ti.com
---
 drivers/mfd/twl-core.c | 104 +++--
 1 file changed, 57 insertions(+), 47 deletions(-)

diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 1827088..e2895a4 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -141,33 +141,28 @@
 
 /*--*/
 
-/* is driver active, bound to a chip? */
-static bool inuse;
-
-/* TWL IDCODE Register value */
-static u32 twl_idcode;
-
-static unsigned int twl_id;
-unsigned int twl_rev(void)
-{
-   return twl_id;
-}
-EXPORT_SYMBOL(twl_rev);
-
 /* Structure for each TWL4030/TWL6030 Slave */
 struct twl_client {
struct i2c_client *client;
struct regmap *regmap;
 };
 
-static struct twl_client *twl_modules;
-
 /* mapping the module id to slave id and base address */
 struct twl_mapping {
unsigned char sid;  /* Slave ID */
unsigned char base; /* base address */
 };
-static struct twl_mapping *twl_map;
+
+struct twl_private {
+   bool ready; /* The core driver is ready to be used */
+   u32 twl_idcode; /* TWL IDCODE Register value */
+   unsigned int twl_id;
+
+   struct twl_mapping *twl_map;
+   struct twl_client *twl_modules;
+};
+
+static struct twl_private *twl_priv;
 
 static struct twl_mapping twl4030_map[] = {
/*
@@ -300,6 +295,12 @@ static inline int twl_get_last_module(void)
 
 /* Exported Functions */
 
+unsigned int twl_rev(void)
+{
+   return twl_priv ? twl_priv-twl_id : 0;
+}
+EXPORT_SYMBOL(twl_rev);
+
 /**
  * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
  * @mod_no: module number
@@ -322,16 +323,17 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned 
num_bytes)
pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
return -EPERM;
}
-   if (unlikely(!inuse)) {
+   if (unlikely(!twl_priv-ready)) {
pr_err(%s: not initialized\n, DRIVER_NAME);
return -EPERM;
}
 
-   sid = twl_map[mod_no].sid;
-   twl = twl_modules[sid];
+   sid = twl_priv-twl_map[mod_no].sid;
+   twl = twl_priv-twl_modules[sid];
 
-   ret = regmap_bulk_write(twl-regmap, twl_map[mod_no].base + reg,
-   value, num_bytes);
+   ret = regmap_bulk_write(twl-regmap,
+   twl_priv-twl_map[mod_no].base + reg, value,
+   num_bytes);
 
if (ret)
pr_err(%s: Write failed (mod %d, reg 0x%02x count %d)\n,
@@ -360,16 +362,17 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned 
num_bytes)
pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
return -EPERM;
}
-   if (unlikely(!inuse)) {
+   if (unlikely(!twl_priv-ready)) {
pr_err(%s: not initialized\n, DRIVER_NAME);
return -EPERM;
}
 
-   sid = twl_map[mod_no].sid;
-   twl = twl_modules[sid];
+   sid = twl_priv-twl_map[mod_no].sid;
+   twl = twl_priv-twl_modules[sid];
 
-   ret = regmap_bulk_read(twl-regmap, twl_map[mod_no].base + reg,
-  value, num_bytes);
+   ret = regmap_bulk_read(twl-regmap,
+  twl_priv-twl_map[mod_no].base + reg, value,
+  num_bytes);
 
if (ret)
pr_err(%s: Read failed (mod %d, reg 0x%02x count %d)\n,
@@ -425,7 +428,7 @@ static int twl_read_idcode_register(void)
goto fail;
}
 
-   err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(twl_idcode),
+   err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(twl_priv-twl_idcode),
REG_IDCODE_7_0, 4);
if (err) {
pr_err(TWL4030: unable to read IDCODE -%d\n, err);
@@ -446,7 +449,7 @@ fail:
  */
 int twl_get_type(void)
 {
-   return TWL_SIL_TYPE(twl_idcode);
+   return TWL_SIL_TYPE(twl_priv-twl_idcode);
 }
 EXPORT_SYMBOL_GPL(twl_get_type);
 
@@ -457,7 +460,7 @@ EXPORT_SYMBOL_GPL(twl_get_type);
  */
 int twl_get_version(void)
 {
-   return TWL_SIL_REV(twl_idcode);
+   return TWL_SIL_REV(twl_priv-twl_idcode);
 }
 EXPORT_SYMBOL_GPL(twl_get_version);
 
@@ -506,8 +509,8 @@ add_numbered_child(unsigned mod_no, const char *name, int 
num,
pr_err(%s: invalid module number %d\n, DRIVER_NAME, mod_no);
return ERR_PTR(-EPERM);
}
-   sid = twl_map[mod_no].sid;
-   twl = twl_modules[sid];
+   sid = twl_priv-twl_map[mod_no].sid;
+   twl = twl_priv-twl_modules[sid];
 
pdev =