Re: [PATCH v4] drivers/tty: Folding Android's keyreset driver in sysRQ

2013-02-27 Thread Mathieu Poirier
On 13-02-27 09:57 AM, Linus Torvalds wrote:
> On Tue, Feb 26, 2013 at 11:33 PM, Dave Airlie  wrote:
>>
>> It looks to me like the weak bit isn't working so well
>>
>> if (platform_sysrq_reset_seq) {
>> for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
>> key = platform_sysrq_reset_seq[i];
>>   6d:   66 8b 8c 00 00 00 00mov0x0(%eax,%eax,1),%cx
>>   74:   00
>>
>> is around where it craps out.
>> gcc version 4.7.2 20121109 (Red Hat 4.7.2-8) (GCC)
>> Fedora 18 machine.
> 
> Hmm. I would love to blame gcc, but no, I think the code is crap.
> 
> The whole 'platform_sysrq_reset_seq[]' thing is broken in current git,
> and it apparently only happens to work by mistake for most of us.
> 
> Doing a "grep" for it shows all three uses:
> 
>git grep platform_sysrq_reset_seq
> 
>   extern unsigned short platform_sysrq_reset_seq[] __weak;
>   if (platform_sysrq_reset_seq) {
> key = platform_sysrq_reset_seq[i];
> 
> and the thing is, if it is declared as an array (not a pointer), then
> I think it is perfectly understandable that when then testing the
> *address* of that array, gcc just says "you're stupid, you're testing
> something that cannot possibly be NULL, so I'll throw your idiotic
> test away".
> 
> And gcc would be completely correct. That test is moronic. You just
> said that platform_sysrq_reset_seq[] was an external array, there is
> no way in hell that is NULL.
> 
> Now, if it was a _pointer_, that would be a different thing entirely.
> A pointer can have a NULL value. A named array, not so much.
> 
> So I *think* the fix might be something like the attached. Totally
> untested. It may compile, or it may not.
> 
> Linus
> 

Your fix is compiling, running and yielding the correct results -
apologies about that.

Acked-by: Mathieu Poirier 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-08-30 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.  A platform device that specify a
reset key-combo should be added to the board file to trigger the
feature.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  161 +
 include/linux/sysrq.h |8 +++
 2 files changed, 169 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..f210853 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,6 +41,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
@@ -49,6 +52,11 @@
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +578,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +620,93 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+
+static int sysrq_probe(struct platform_device *pdev)
+{
+   struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+
+   /*
+* No sequence of keys to trigger on,
+* assuming default sysRQ behavior.
+*/
+   if (pdata) {
+   atomic_set(&restart_requested, 0);
+   sysrq_handler.private = pdata;
+   } else
+   sysrq_handler.private = NULL;
+
+   /* FETCH DT INFO HERE */
+
+   return 0;
+
+}
+
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   /* Is the code is of interest to us */
+   if (!test_bit(code, state->keybit))
+   return processed;
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value)
+   return processed;
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &&
+   state->key_down_ctn == state->key_down_target) {
+   state->restart_disabled = 1;
+   if (atomic_read(&restart_requested))
+   panic("keyboard reset failed, %d - panic\n",
+atomic_read(&restart_requested));
+   if (state->reset_fn) {
+   ret = state->reset_fn();
+   atomic_set(&restart_requested, ret);
+   } else {
+   pr_info("keyboard reset\n");
+   schedule_work(&restart_work);
+   atomic_inc(&restart_requested);
+   }
+   }
+
+   /* no need to suppress keyreset characters */
+   state->active = false;
+
+   return processed;

Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-08-31 Thread Mathieu Poirier
On 12-08-30 05:01 PM, Dmitry Torokhov wrote:
> Hi Matthieu,
> 
> On Thu, Aug 30, 2012 at 04:30:54PM -0600, mathieu.poir...@linaro.org wrote:
>> From: "Mathieu J. Poirier" 
>>
>> This patch adds keyreset functionality to the sysrq driver. It
>> allows certain button/key combinations to be used in order to
>> trigger device resets.
>>
>> The first time the key-combo is detected a work function that syncs
>> the filesystems is scheduled and the kernel rebooted. If all the keys
>> are released and then pressed again, it calls panic. Reboot on panic
>> should be set for this to work.  A platform device that specify a
>> reset key-combo should be added to the board file to trigger the
>> feature.
>
> Why do we need to involve a platform device and not use, for example, a module
> parameter, that could be set up from userspace?

The platform device comes from the original design and was included to
minimise the amount of changes in code that make use of the current
keyreset driver.

I am definitely willing to explore the possibility of adding module
parameter to complement the platform data but again, to avoid impacting
board code I'm in favour of keeping the platform data/device - get back
to me if you disagree.

Thinking back on this it may be better to call 'platform_driver_probe'
rather than 'platform_driver_register'.  That way one wouldn't have to
instantiate a platform_device.

> 
> Also, why do we need reset_fn() and not simply invoke SysRq-B handler
> that should call ctrl_alt_del() for us?

The reset_fn() gives an implementer the chance of calling some custom
function before the reset sequence is started and in my opinion should
stay.  On the flip side I'm not sure that I understand what you mean by
"SysRq-B handler" - are you talking about the "sysrq_reboot_op" ?
Please expand on that ?

Thanks for the review and comments,
Mathieu.

> 
> Thanks.
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-08-31 Thread Mathieu Poirier
On 12-08-31 04:02 PM, Alan Cox wrote:
>>> Why do we need to involve a platform device and not use, for example, a 
>>> module
>>> parameter, that could be set up from userspace?
>>
>> The platform device comes from the original design and was included to
>> minimise the amount of changes in code that make use of the current
>> keyreset driver.
> 
> The platform device is IMHO the right answer. In this class of devices
> the stuff is compiled in, the userspace is Android, there are no modules
> and there is no reason for it to be configurable.
> 
>> I am definitely willing to explore the possibility of adding module
>> parameter to complement the platform data but again, to avoid impacting
>> board code I'm in favour of keeping the platform data/device - get back
>> to me if you disagree.
>>
>> Thinking back on this it may be better to call 'platform_driver_probe'
>> rather than 'platform_driver_register'.  That way one wouldn't have to
>> instantiate a platform_device.
>>
>>>
>>> Also, why do we need reset_fn() and not simply invoke SysRq-B handler
>>> that should call ctrl_alt_del() for us?
>>
>> The reset_fn() gives an implementer the chance of calling some custom
>> function before the reset sequence is started and in my opinion should

I did not express myself clearly - with reset_fn() a system can do
whatever it wants when a specific series of keys is pressed.

Granted that the next steps are most likely converging toward rebooting
the system - but it may not be right away and depending on the
circumstances a reboot could be avoided altogether.

> 
> So why wouldn't that already be using the reset notifiers ?

I am not familiar with the "reset notifiers" that have been referred to
but a little bit of research indicate that a registering subsystem gets
notified when the event of interest (in this case a reboot) happens.

I understand your proposition here but aren't we loosing flexibility in
what we can achieve when the event has been triggered ?

What do you think of adding a keyreset event that would be fired (and
caught by a registering subsystem) instead of calling reset_fn() ?

Thanks,
Mathieu.

> 
> Alan
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-08-31 Thread Mathieu Poirier
On 12-08-31 04:41 PM, Dmitry Torokhov wrote:
> On Fri, Aug 31, 2012 at 11:02:27PM +0100, Alan Cox wrote:
 Why do we need to involve a platform device and not use, for example, a 
 module
 parameter, that could be set up from userspace?
>>>
>>> The platform device comes from the original design and was included to
>>> minimise the amount of changes in code that make use of the current
>>> keyreset driver.
>>
>> The platform device is IMHO the right answer. In this class of devices
>> the stuff is compiled in, the userspace is Android, there are no modules
>> and there is no reason for it to be configurable.
> 
> It does not matter if it is built in or not, /sys/module/XXX/parameters
> is still there, and while havig it in kernel is "easy" you could as
> easily stuff needed data into a sysfs attribute during booting.
> 
> And we should be able to get this from DT even without the platform
> device (this was the next step, wasn't it?).

Correct - my hope was to get the main functionality accepted before
adding DT support.  Do you think the lack of DT support is a blocker for
acceptance ?  Please confirm.

Mathieu.

> 
> Thanks.
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-09-04 Thread Mathieu Poirier
On 12-08-31 05:22 PM, Dmitry Torokhov wrote:
> On Fri, Aug 31, 2012 at 04:57:04PM -0600, Mathieu Poirier wrote:
>> On 12-08-31 04:41 PM, Dmitry Torokhov wrote:
>>> On Fri, Aug 31, 2012 at 11:02:27PM +0100, Alan Cox wrote:
>>>>>> Why do we need to involve a platform device and not use, for example, a 
>>>>>> module
>>>>>> parameter, that could be set up from userspace?
>>>>>
>>>>> The platform device comes from the original design and was included to
>>>>> minimise the amount of changes in code that make use of the current
>>>>> keyreset driver.
>>>>
>>>> The platform device is IMHO the right answer. In this class of devices
>>>> the stuff is compiled in, the userspace is Android, there are no modules
>>>> and there is no reason for it to be configurable.
>>>
>>> It does not matter if it is built in or not, /sys/module/XXX/parameters
>>> is still there, and while havig it in kernel is "easy" you could as
>>> easily stuff needed data into a sysfs attribute during booting.
>>>
>>> And we should be able to get this from DT even without the platform
>>> device (this was the next step, wasn't it?).
>>
>> Correct - my hope was to get the main functionality accepted before
>> adding DT support.  Do you think the lack of DT support is a blocker for
>> acceptance ?  Please confirm.
>>
> 
> No, lack of DT is not a blocker, but I am unconvinced that we need
> platform device.
> 
> Thanks,
> 

A platform device is really easy to spin-off in a board file and once it
is there you don't have to worry about other loose ends to tie in before
the solution is functional.

I don't mind supplementing the current proposition with a module
parameter interface to get the "key_down" and "key_up" sequences.

Which brings us to the "reset_fn()" function - in my opinion it offers
significant advantages and should be kept in the design.  What I'm not
so clear about is on the implementation.  Should it be kept as part of a
platform data or be implemented as a notifier as suggested by Alan.  I
am looking for guidance here and suggestions are encouraged.

Regards,
Mathieu.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-10-05 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

Andrew,

After requesting a number of changes that, to my understanding
have been implemented, I have not been able to get the attention
of the subsystem maintainer on this patch.

If there are still issues, I'm open to making changes but I want
to make sure it doesn't get forgotten.  If there no objections,
would you consider queuint it ?

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.

A platform device that specify a reset key-combo should be added to
the board file to trigger the feature.  Alternatively keys can be
passed to the driver via the "/sys/module/sysrq" interface.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Cc: a...@lxorguk.ukuu.org.uk
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  308 +
 include/linux/sysrq.h |8 ++
 2 files changed, 316 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..c44056f 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,14 +41,30 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
 
+#define KEY_DOWN_MAX   20 /* how  many is enough ? */
+int keyreset_param[KEY_DOWN_MAX];
+struct mutex sysrq_mutex;
+static struct sysrq_state *sysrq_handle;
+
 /* Whether we react on sysrq keys or just ignore them */
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +586,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +628,101 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+
+static int sysrq_probe(struct platform_device *pdev)
+{
+   struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+
+   /*
+* No sequence of keys to trigger on,
+* assuming default sysRQ behavior.
+*/
+   if (pdata) {
+   atomic_set(&restart_requested, 0);
+   sysrq_handler.private = pdata;
+   } else
+   sysrq_handler.private = NULL;
+
+   /* FETCH DT INFO HERE */
+
+   return 0;
+
+}
+
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   mutex_lock(&sysrq_mutex);
+
+   /* Is the code of interest to us */
+   if (!test_bit(code, state->keybit)) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &am

Re: [PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-10-05 Thread Mathieu Poirier
On 12-10-05 12:16 PM, Dmitry Torokhov wrote:
> On Fri, Oct 05, 2012 at 11:59:29AM -0600, mathieu.poir...@linaro.org wrote:
>> From: "Mathieu J. Poirier" 
>>
>> Andrew,
>>
>> After requesting a number of changes that, to my understanding
>> have been implemented, I have not been able to get the attention
>> of the subsystem maintainer on this patch.
>>
>> If there are still issues, I'm open to making changes but I want
>> to make sure it doesn't get forgotten.  If there no objections,
>> would you consider queuint it ?
> 
> Mathieu,
> 
> I have the same objection as before: using platform device solely for
> the purpose of passing some data from board code to the driver. Surely
> there are other ways of passing this bit of data... What about, for
> example, making it an empty weak symbol so that board code could
> override it with strong one?

Thanks for the comments - I will implement a weak function in the
keyreset driver.

Mathieu.

> 
> Thanks.
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RESEND PATCH v3] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-09-24 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

The last version of this patch was sent a week ago but did not
generate comments or an acknowledgement.  It is being resent
after a rebase on 3.6-rc7.

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.

A platform device that specify a reset key-combo should be added to
the board file to trigger the feature.  Alternatively keys can be
passed to the driver via the "/sys/module/sysrq" interface.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  308 +
 include/linux/sysrq.h |8 ++
 2 files changed, 316 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..c44056f 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,14 +41,30 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
 
+#define KEY_DOWN_MAX   20 /* how  many is enough ? */
+int keyreset_param[KEY_DOWN_MAX];
+struct mutex sysrq_mutex;
+static struct sysrq_state *sysrq_handle;
+
 /* Whether we react on sysrq keys or just ignore them */
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +586,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +628,101 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+
+static int sysrq_probe(struct platform_device *pdev)
+{
+   struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+
+   /*
+* No sequence of keys to trigger on,
+* assuming default sysRQ behavior.
+*/
+   if (pdata) {
+   atomic_set(&restart_requested, 0);
+   sysrq_handler.private = pdata;
+   } else
+   sysrq_handler.private = NULL;
+
+   /* FETCH DT INFO HERE */
+
+   return 0;
+
+}
+
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   mutex_lock(&sysrq_mutex);
+
+   /* Is the code of interest to us */
+   if (!test_bit(code, state->keybit)) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &&
+   state->key_down_ctn == state->key_down_target) {
+   state->restart_disabled = 1;
+   if (atomic_read(&restart_requested))
+

[PATCH 01/57] power: ab8500_bm: Charger current step-up/down

2012-09-25 Thread mathieu . poirier
From: Johan Bjornstedt 

There is no state machine in the AB to step up/down
the charger current to avoid dips and spikes on VBUS
and VBAT when charging is started.
Instead this is implemented in SW

Signed-off-by: Johan Bjornstedt 
Signed-off-by: Mattias Wallin 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_charger.c |  172 +++-
 1 files changed, 133 insertions(+), 39 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index d4f0c98..3ceb788 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -77,6 +77,9 @@
 /* Lowest charger voltage is 3.39V -> 0x4E */
 #define LOW_VOLT_REG   0x4E
 
+/* Step up/down delay in us */
+#define STEP_UDELAY1000
+
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
USB_STAT_NOT_CONFIGURED,
@@ -934,6 +937,88 @@ static int ab8500_charger_get_usb_cur(struct 
ab8500_charger *di)
 }
 
 /**
+ * ab8500_charger_set_current() - set charger current
+ * @di:pointer to the ab8500_charger structure
+ * @ich:   charger current, in mA
+ * @reg:   select what charger register to set
+ *
+ * Set charger current.
+ * There is no state machine in the AB to step up/down the charger
+ * current to avoid dips and spikes on MAIN, VBUS and VBAT when
+ * charging is started. Instead we need to implement
+ * this charger current step-up/down here.
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8500_charger_set_current(struct ab8500_charger *di,
+   int ich, int reg)
+{
+   int ret, i;
+   int curr_index, prev_curr_index, shift_value;
+   u8 reg_value;
+
+   switch (reg) {
+   case AB8500_MCH_IPT_CURLVL_REG:
+   shift_value = MAIN_CH_INPUT_CURR_SHIFT;
+   curr_index = ab8500_current_to_regval(ich);
+   break;
+   case AB8500_USBCH_IPT_CRNTLVL_REG:
+   shift_value = VBUS_IN_CURR_LIM_SHIFT;
+   curr_index = ab8500_vbus_in_curr_to_regval(ich);
+   break;
+   case AB8500_CH_OPT_CRNTLVL_REG:
+   shift_value = 0;
+   curr_index = ab8500_current_to_regval(ich);
+   break;
+   default:
+   dev_err(di->dev, "%s current register not valid\n", __func__);
+   return -ENXIO;
+   }
+
+   if (curr_index < 0) {
+   dev_err(di->dev, "requested current limit out-of-range\n");
+   return -ENXIO;
+   }
+
+   ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+   reg, ®_value);
+   if (ret < 0) {
+   dev_err(di->dev, "%s read failed\n", __func__);
+   return ret;
+   }
+   prev_curr_index = (reg_value >> shift_value);
+
+   /* only update current if it's been changed */
+   if (prev_curr_index == curr_index)
+   return 0;
+
+   dev_dbg(di->dev, "%s set charger current: %d mA for reg: 0x%02x\n",
+   __func__, ich, reg);
+
+   if (prev_curr_index > curr_index) {
+   for (i = prev_curr_index - 1; i >= curr_index; i--) {
+   ret = abx500_set_register_interruptible(di->dev,
+   AB8500_CHARGER, reg, (u8) i << shift_value);
+   if (ret) {
+   dev_err(di->dev, "%s write failed\n", __func__);
+   return ret;
+   }
+   usleep_range(STEP_UDELAY, STEP_UDELAY * 2);
+   }
+   } else {
+   for (i = prev_curr_index + 1; i <= curr_index; i++) {
+   ret = abx500_set_register_interruptible(di->dev,
+   AB8500_CHARGER, reg, (u8) i << shift_value);
+   if (ret) {
+   dev_err(di->dev, "%s write failed\n", __func__);
+   return ret;
+   }
+   usleep_range(STEP_UDELAY, STEP_UDELAY * 2);
+   }
+   }
+   return ret;
+}
+
+/**
  * ab8500_charger_set_vbus_in_curr() - set VBUS input current limit
  * @di:pointer to the ab8500_charger structure
  * @ich_in:charger input current limit
@@ -944,8 +1029,6 @@ static int ab8500_charger_get_usb_cur(struct 
ab8500_charger *di)
 static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
int ich_in)
 {
-   int ret;
-   int input_curr_index;
int min_value;
 
/* We should always use to lowest current limit */
@@ -964,19 +1047,38 @@ static int ab8500_charger_set_vbus_in_curr(struct 
ab8500_charger *di,
break;
}
 
-   input_curr_index = ab

[PATCH 04/57] power: ab8500: bm: movimg back to ab8500 platform data managment

2012-09-25 Thread mathieu . poirier
From: Philippe Langlais 

Signed-off-by: Philippe Langlais 
Signed-off-by: Mathieu Poirier 
---
 drivers/power/ab8500_btemp.c  |8 ++--
 drivers/power/ab8500_charger.c|9 +++--
 drivers/power/ab8500_fg.c |8 ++--
 drivers/power/abx500_chargalg.c   |7 ---
 include/linux/mfd/abx500/ab8500.h |7 ++-
 5 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 94a3ee8..41a8ce4 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -973,14 +973,9 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
 {
int irq, i, ret = 0;
u8 val;
-   struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
+   struct ab8500_platform_data *plat_data;
struct ab8500_btemp *di;
 
-   if (!plat_data) {
-   dev_err(&pdev->dev, "No platform data\n");
-   return -EINVAL;
-   }
-
di = kzalloc(sizeof(*di), GFP_KERNEL);
if (!di)
return -ENOMEM;
@@ -993,6 +988,7 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
di->initialized = false;
 
/* get btemp specific platform data */
+   plat_data = dev_get_platdata(di->parent->dev);
di->pdata = plat_data->btemp;
if (!di->pdata) {
dev_err(di->dev, "no btemp platform data supplied\n");
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 3ceb788..22076f5 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2628,14 +2628,9 @@ static int __devexit ab8500_charger_remove(struct 
platform_device *pdev)
 static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 {
int irq, i, charger_status, ret = 0;
-   struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
+   struct ab8500_platform_data *plat_data;
struct ab8500_charger *di;
 
-   if (!plat_data) {
-   dev_err(&pdev->dev, "No platform data\n");
-   return -EINVAL;
-   }
-
di = kzalloc(sizeof(*di), GFP_KERNEL);
if (!di)
return -ENOMEM;
@@ -2649,6 +2644,8 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
spin_lock_init(&di->usb_state.usb_lock);
 
/* get charger specific platform data */
+   plat_data = dev_get_platdata(di->parent->dev);
+
di->pdata = plat_data->charger;
if (!di->pdata) {
dev_err(di->dev, "no charger platform data supplied\n");
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index af792a8..c098ddd 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2446,14 +2446,9 @@ static int __devinit ab8500_fg_probe(struct 
platform_device *pdev)
 {
int i, irq;
int ret = 0;
-   struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data;
+   struct ab8500_platform_data *plat_data;
struct ab8500_fg *di;
 
-   if (!plat_data) {
-   dev_err(&pdev->dev, "No platform data\n");
-   return -EINVAL;
-   }
-
di = kzalloc(sizeof(*di), GFP_KERNEL);
if (!di)
return -ENOMEM;
@@ -2466,6 +2461,7 @@ static int __devinit ab8500_fg_probe(struct 
platform_device *pdev)
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
/* get fg specific platform data */
+   plat_data = dev_get_platdata(di->parent->dev);
di->pdata = plat_data->fg;
if (!di->pdata) {
dev_err(di->dev, "no fg platform data supplied\n");
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 804b88c..032b27d 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -220,6 +220,7 @@ enum maxim_ret {
  */
 struct abx500_chargalg {
struct device *dev;
+   struct ab8500 *parent;
int charge_status;
int eoc_cnt;
int rch_cnt;
@@ -1802,7 +1803,7 @@ static int __devexit abx500_chargalg_remove(struct 
platform_device *pdev)
 
 static int __devinit abx500_chargalg_probe(struct platform_device *pdev)
 {
-   struct abx500_bm_plat_data *plat_data;
+   struct ab8500_platform_data *plat_data;
int ret = 0;
 
struct abx500_chargalg *di =
@@ -1812,8 +1813,8 @@ static int __devinit abx500_chargalg_probe(struct 
platform_device *pdev)
 
/* get device struct */
di->dev = &pdev->dev;
-
-   plat_data = pdev->dev.platform_data;
+   di->parent = dev_get_drvdata(pdev->dev.parent);
+   plat_data = dev_get_platdata(di->parent->dev);
di->pdata = plat_data->chargalg;
di->bat = plat_data->battery;
 

[PATCH 09/57] power: ab8500_fg: usleep_range instead of short msleep

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Signed-off-by: Jonas ABERG 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Johan BJORNSTEDT 
---
 drivers/power/ab8500_fg.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 1e02b00..0db17c7 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -957,7 +957,7 @@ static int ab8500_fg_load_comp_volt_to_capacity(struct 
ab8500_fg *di)
do {
vbat += ab8500_fg_bat_voltage(di);
i++;
-   msleep(5);
+   usleep_range(5000, 5001);
} while (!ab8500_fg_inst_curr_done(di));
 
ab8500_fg_inst_curr_finalize(di, &di->inst_curr);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 18/57] power: Add sysfs interfaces for capacity

2012-09-25 Thread mathieu . poirier
From: Daniel WILLERUD 

Switchable depending on whether capacity scaling is enabled

Signed-off-by: Marcus Cooper 
Signed-off-by: Daniel WILLERUD 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |   57 -
 1 files changed, 56 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 8507254..46010ec 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -266,7 +266,6 @@ static enum power_supply_property ab8500_fg_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
-   POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
 };
 
@@ -2543,6 +2542,54 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di)
 
return ret;
 }
+
+static ssize_t ab8500_show_capacity(struct device *dev,
+struct device_attribute *attr,
+char *buf)
+{
+   struct power_supply *psy = dev_get_drvdata(dev);
+   struct ab8500_fg *di;
+   int capacity;
+
+   di = to_ab8500_fg_device_info(psy);
+
+   if (di->bat->capacity_scaling)
+   capacity = di->bat_cap.cap_scale.scaled_cap;
+   else
+   capacity = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
+
+   return scnprintf(buf, PAGE_SIZE, "%d\n", capacity);
+}
+
+static struct device_attribute ab8500_fg_sysfs_psy_attrs[] = {
+   __ATTR(capacity, S_IRUGO, ab8500_show_capacity, NULL),
+};
+
+static int ab8500_fg_sysfs_psy_create_attrs(struct device *dev)
+{
+   unsigned int i;
+
+   for (i = 0; i < ARRAY_SIZE(ab8500_fg_sysfs_psy_attrs); i++)
+   if (device_create_file(dev, &ab8500_fg_sysfs_psy_attrs[i]))
+   goto sysfs_psy_create_attrs_failed;
+
+   return 0;
+
+sysfs_psy_create_attrs_failed:
+   dev_err(dev, "Failed creating sysfs psy attrs.\n");
+   while (i--)
+   device_remove_file(dev, &ab8500_fg_sysfs_psy_attrs[i]);
+
+   return -EIO;
+}
+
+static void ab8500_fg_sysfs_psy_remove_attrs(struct device *dev)
+{
+   unsigned int i;
+
+   for (i = 0; i < ARRAY_SIZE(ab8500_fg_sysfs_psy_attrs); i++)
+   (void)device_remove_file(dev, &ab8500_fg_sysfs_psy_attrs[i]);
+}
 /* Exposure to the sysfs interface <> */
 
 #if defined(CONFIG_PM)
@@ -2599,6 +2646,7 @@ static int __devexit ab8500_fg_remove(struct 
platform_device *pdev)
ab8500_fg_sysfs_exit(di);
 
flush_scheduled_work();
+   ab8500_fg_sysfs_psy_remove_attrs(di->fg_psy.dev);
power_supply_unregister(&di->fg_psy);
platform_set_drvdata(pdev, NULL);
kfree(di);
@@ -2754,6 +2802,13 @@ static int __devinit ab8500_fg_probe(struct 
platform_device *pdev)
goto free_irq;
}
 
+   ret = ab8500_fg_sysfs_psy_create_attrs(di->fg_psy.dev);
+   if (ret) {
+   dev_err(di->dev, "failed to create FG psy\n");
+   ab8500_fg_sysfs_exit(di);
+   goto free_irq;
+   }
+
/* Calibrate the fg first time */
di->flags.calibrate = true;
di->calib_state = AB8500_FG_CALIB_INIT;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 24/57] power: ab8500_fg: Adjust for RF bursts voltage drops.

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

Changed conditions for restarting low battery measurements counter
and adjusted the interval between measurements to avoid RF burst
induced voltage drops, and to shorten time to decide to shut down.

Signed-off-by: Hakan Berg 
Signed-off-by: Martin Bergstrom 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
Reviewed-by: Marcus COOPER 
---
 drivers/power/ab8500_fg.c |   44 ++--
 1 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 7c42150..861927d 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -42,7 +42,7 @@
 
 #define NBR_AVG_SAMPLES20
 
-#define LOW_BAT_CHECK_INTERVAL (2 * HZ)
+#define LOW_BAT_CHECK_INTERVAL (HZ / 16) /* 62.5 ms */
 
 #define VALID_CAPACITY_SEC (45 * 60) /* 45 minutes */
 #define BATT_OK_MIN2360 /* mV */
@@ -168,6 +168,7 @@ struct inst_curr_result_list {
  * @recovery_cnt:  Counter for recovery mode
  * @high_curr_cnt: Counter for high current mode
  * @init_cnt:  Counter for init mode
+ * @low_bat_cntCounter for number of consecutive low battery 
measures
  * @nbr_cceoc_irq_cnt  Counter for number of CCEOC irqs received since enabled
  * @recovery_needed:   Indicate if recovery is needed
  * @high_curr_mode:Indicate if we're in high current mode
@@ -210,6 +211,7 @@ struct ab8500_fg {
int recovery_cnt;
int high_curr_cnt;
int init_cnt;
+   int low_bat_cnt;
int nbr_cceoc_irq_cnt;
bool recovery_needed;
bool high_curr_mode;
@@ -1882,25 +1884,29 @@ static void ab8500_fg_low_bat_work(struct work_struct 
*work)
 
/* Check if LOW_BAT still fulfilled */
if (vbat < di->bat->fg_params->lowbat_threshold) {
-   di->flags.low_bat = true;
-   dev_warn(di->dev, "Battery voltage still LOW\n");
-
-   /*
-* We need to re-schedule this check to be able to detect
-* if the voltage increases again during charging
-*/
-   queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
-   round_jiffies(LOW_BAT_CHECK_INTERVAL));
+   /* Is it time to shut down? */
+   if (di->low_bat_cnt < 1) {
+   di->flags.low_bat = true;
+   dev_warn(di->dev, "Shut down pending...\n");
+   } else {
+   /*
+   * Else we need to re-schedule this check to be able
+   * to detect if the voltage increases again during
+   * charging or due to decreasing load.
+   */
+   di->low_bat_cnt--;
+   dev_warn(di->dev, "Battery voltage still LOW\n");
+   queue_delayed_work(di->fg_wq, &di->fg_low_bat_work,
+   round_jiffies(LOW_BAT_CHECK_INTERVAL));
+   }
} else {
-   di->flags.low_bat = false;
+   di->flags.low_bat_delay = false;
+   di->low_bat_cnt = 10;
dev_warn(di->dev, "Battery voltage OK again\n");
}
 
/* This is needed to dispatch LOW_BAT */
ab8500_fg_check_capacity_limits(di, false);
-
-   /* Set this flag to check if LOW_BAT IRQ still occurs */
-   di->flags.low_bat_delay = false;
 }
 
 /**
@@ -2059,6 +2065,10 @@ static irqreturn_t ab8500_fg_lowbatf_handler(int irq, 
void *_di)
 {
struct ab8500_fg *di = _di;
 
+   /*
+* Initiate handling in ab8500_fg_low_bat_work() if not already
+* initiated.
+*/
if (!di->flags.low_bat_delay) {
dev_warn(di->dev, "Battery voltage is below LOW threshold\n");
di->flags.low_bat_delay = true;
@@ -2748,6 +2758,12 @@ static int __devinit ab8500_fg_probe(struct 
platform_device *pdev)
INIT_DELAYED_WORK_DEFERRABLE(&di->fg_check_hw_failure_work,
ab8500_fg_check_hw_failure_work);
 
+   /* Reset battery low voltage flag */
+   di->flags.low_bat = false;
+
+   /* Initialize low battery counter */
+   di->low_bat_cnt = 10;
+
/* Initialize OVV, and other registers */
ret = ab8500_fg_init_hw_registers(di);
if (ret) {
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 31/57] power: ab8500_fg: fix to use correct battery charge full design

2012-09-25 Thread mathieu . poirier
From: Rajkumar Kasirajan 

If battery is not identified while fg probe, mah_max_design gets
initialized with unknown battery's charge full design. Reinitialize
mah_max_design if battery is identified after fg probe.

Signed-off-by: Rajkumar Kasirajan 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
Reviewed-by: Vijaya Kumar K-1 
Reviewed-by: Marcus COOPER 
Reviewed-by: Olivier CLERGEAUD 
Reviewed-by: Arun MURTHY 
Reviewed-by: Rupesh KUMAR 
Reviewed-by: Rabin VINCENT 
---
 drivers/power/ab8500_fg.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 0e71e7e..5e4a46b 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2258,9 +2258,9 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, 
void *data)
case POWER_SUPPLY_PROP_TECHNOLOGY:
switch (ext->type) {
case POWER_SUPPLY_TYPE_BATTERY:
-   if (!di->flags.batt_id_received) {
+   if (!di->flags.batt_id_received &&
+   di->bat->batt_id != BATTERY_UNKNOWN) {
const struct abx500_battery_type *b;
-
b = 
&(di->bat->bat_type[di->bat->batt_id]);
 
di->flags.batt_id_received = true;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 34/57] power: ab8500_fg: add power cut feature for ab8505

2012-09-25 Thread mathieu . poirier
From: Rikard Olsson 

Add support for a power cut feature which allows user to
configure when ab8505 should shut down system due to low
battery.

Signed-off-by: Rikard Olsson 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Martin SJOBLOM 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c|  488 +-
 include/linux/mfd/abx500.h   |   10 +
 include/linux/mfd/abx500/ab8500-bm.h |8 +
 3 files changed, 502 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 5e4a46b..fde189a 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2351,6 +2351,64 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg 
*di)
dev_err(di->dev, "BattOk init write failed.\n");
goto out;
}
+
+   if ((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+   abx500_get_chip_id(di->dev) >= AB8500_CUT2P0) {
+   ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+   AB8505_RTC_PCUT_MAX_TIME_REG,
+di->bat->fg_params->pcut_max_time);
+
+   if (ret) {
+   dev_err(di->dev,
+   "%s write failed 
AB8505_RTC_PCUT_MAX_TIME_REG\n",
+__func__);
+   goto out;
+   };
+
+   ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+   AB8505_RTC_PCUT_FLAG_TIME_REG,
+di->bat->fg_params->pcut_flag_time);
+
+   if (ret) {
+   dev_err(di->dev,
+   "%s write failed AB8505_RTC_PCUT_FLAG_TIME_REG\n",
+__func__);
+   goto out;
+   };
+
+   ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+   AB8505_RTC_PCUT_RESTART_REG,
+   di->bat->fg_params->pcut_max_restart);
+
+   if (ret) {
+   dev_err(di->dev,
+   "%s write failed AB8505_RTC_PCUT_RESTART_REG\n",
+__func__);
+   goto out;
+   };
+
+   ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+   AB8505_RTC_PCUT_DEBOUNCE_REG,
+di->bat->fg_params->pcut_debunce_time);
+
+   if (ret) {
+   dev_err(di->dev,
+   "%s write failed AB8505_RTC_PCUT_DEBOUNCE_REG\n",
+__func__);
+   goto out;
+   };
+
+   ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+   AB8505_RTC_PCUT_CTL_STATUS_REG,
+di->bat->fg_params->pcut_enable);
+
+   if (ret) {
+   dev_err(di->dev,
+   "%s write failed AB8505_RTC_PCUT_CTL_STATUS_REG\n",
+__func__);
+   goto out;
+   };
+   }
 out:
return ret;
 }
@@ -2572,22 +2630,433 @@ static ssize_t ab8500_show_capacity(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%d\n", capacity);
 }
 
+static ssize_t ab8505_powercut_flagtime_read(struct device *dev,
+struct device_attribute *attr,
+char *buf)
+{
+   int ret;
+   u8 reg_value;
+   struct power_supply *psy = dev_get_drvdata(dev);
+   struct ab8500_fg *di;
+
+   di = to_ab8500_fg_device_info(psy);
+
+   ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+   AB8505_RTC_PCUT_FLAG_TIME_REG, ®_value);
+
+   if (ret < 0) {
+   dev_err(dev, "Failed to read AB8505_RTC_PCUT_FLAG_TIME_REG\n");
+   goto fail;
+   }
+
+   return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+   return ret;
+}
+
+static ssize_t ab8505_powercut_flagtime_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+   int ret;
+   long unsigned reg_value;
+   struct power_supply *psy = dev_get_drvdata(dev);
+   struct ab8500_fg *di;
+
+   di = to_ab8500_fg_device_info(psy);
+
+   if (kstrtoul(buf, 10, ®_value) != 0)
+   goto fail;
+
+   if (reg_value > 0x7F) {
+   dev_err(dev, "Incorrect parameter, echo 0 (1.98s) - 127 
(15.625ms) for flagtime\n");
+   goto fail;
+   }
+
+   ret = abx500_set_register_interruptibl

[PATCH 51/57] power: ab8500: Re-alignment with internal developement.

2012-09-25 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

A lot of developement happened internally since the first
mainlining of the battery managmenent driver.  Most of the
new code can be historically accounted for but some of it
can't.

This patch is a gathering of the code for which history was
lost but still relevant to the well being of the driver.

Signed-off-by: Mathieu Poirier 
---
 drivers/power/ab8500_charger.c  |2 +-
 drivers/power/abx500_chargalg.c |   66 +++
 2 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 1290470..3a97012 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -720,7 +720,7 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_C_HS_CHIRP:
-   case USB_STAT_ACA_RID_C_NM:
+   case USB_STAT_ACA_RID_C_NM:
di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5;
di->is_aca_rid = 1;
break;
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 1df238f..636d970 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -27,7 +27,7 @@
 #include 
 
 /* Watchdog kick interval */
-#define CHG_WD_INTERVAL(6 * HZ)
+#define CHG_WD_INTERVAL(60 * HZ)
 
 /* End-of-charge criteria counter */
 #define EOC_COND_CNT   10
@@ -513,7 +513,7 @@ static int abx500_chargalg_kick_watchdog(struct 
abx500_chargalg *di)
 static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
int vset, int iset)
 {
-   static int ab8500_chargalg_ex_ac_enable_toggle;
+   static int abx500_chargalg_ex_ac_enable_toggle;
 
if (!di->ac_chg || !di->ac_chg->ops.enable)
return -ENXIO;
@@ -529,10 +529,10 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg 
*di, int enable,
 
/*enable external charger*/
if (enable && di->ac_chg->external &&
-   !ab8500_chargalg_ex_ac_enable_toggle) {
+   !abx500_chargalg_ex_ac_enable_toggle) {
blocking_notifier_call_chain(&charger_notifier_list,
0, di->dev);
-   ab8500_chargalg_ex_ac_enable_toggle++;
+   abx500_chargalg_ex_ac_enable_toggle++;
}
 
return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset);
@@ -899,6 +899,27 @@ static void handle_maxim_chg_curr(struct abx500_chargalg 
*di)
}
 }
 
+static void abx500_chargalg_check_safety_timer(struct abx500_chargalg *di)
+{
+   /*
+* The safety timer will not be started until the capacity reported
+* from the FG algorithm is 100%. Then we know that the amount of
+* charge that's gone into the battery is enough for the battery
+* to be full. If it has not reached end-of-charge before the safety
+* timer has expired then we know that the battery is overcharged
+* and charging will be stopped to protect the battery.
+*/
+   if (di->batt_data.percent == 100 &&
+   !timer_pending(&di->safety_timer)) {
+   abx500_chargalg_start_safety_timer(di);
+   dev_dbg(di->dev, "start safety timer\n");
+   } else if (di->batt_data.percent != 100 &&
+   timer_pending(&di->safety_timer)) {
+   abx500_chargalg_stop_safety_timer(di);
+   dev_dbg(di->dev, "stop safety timer\n");
+   }
+}
+
 static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data)
 {
struct power_supply *psy;
@@ -1125,6 +1146,10 @@ static int abx500_chargalg_get_ext_psy_data(struct 
device *dev, void *data)
switch (ext->type) {
case POWER_SUPPLY_TYPE_BATTERY:
di->batt_data.volt = ret.intval / 1000;
+   if (di->batt_data.volt >= BATT_OVV_VALUE)
+   di->events.batt_ovv = true;
+   else
+   di->events.batt_ovv = false;
break;
case POWER_SUPPLY_TYPE_MAINS:
di->chg_info.ac_volt = ret.intval / 1000;
@@ -1214,7 +1239,6 @@ static int abx500_chargalg_get_ext_psy_data(struct device 
*dev, void *data)
}
break;
case POWER_SUPPLY_PROP_CAPACITY:
-   di->batt_data.percent = ret.intval;
if (!capacity_updated)
di->batt_data.percent = ret.intval;
 

[PATCH 54/57] power: ab8500_charger: Use USBLink1Status Register

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

The newer AB's such as the AB8505, AB9540 etc include a
USBLink1 Status register which detects a larger range of
external devices. This should be used instead of the
USBLine Status register.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Hakan BERG 
Reviewed-by: Yang QU 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c |   22 --
 1 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 3a97012..7f8f362 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2258,8 +2258,13 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
 * to start the charging process. but by jumping
 * thru a few hoops it can be forced to start.
 */
-   ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
-   AB8500_USB_LINE_STAT_REG, &val);
+   if (is_ab8500(di->parent))
+   ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+   AB8500_USB_LINE_STAT_REG, &val);
+   else
+   ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+   AB8500_USB_LINK1_STAT_REG, &val);
+
if (ret >= 0)
dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val);
else
@@ -2299,10 +2304,15 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
AB8500_MCH_IPT_CURLVL_REG,
0x01, 0x00);
/*Check link status*/
-   ret = abx500_get_register_interruptible(di->dev,
-   AB8500_USB,
-   AB8500_USB_LINE_STAT_REG,
-   &val);
+   if (is_ab8500(di->parent))
+   ret = abx500_get_register_interruptible(di->dev,
+   AB8500_USB, AB8500_USB_LINE_STAT_REG,
+   &val);
+   else
+   ret = abx500_get_register_interruptible(di->dev,
+   AB8500_USB, AB8500_USB_LINK1_STAT_REG,
+   &val);
+
dev_dbg(di->dev, "USB link status= 0x%02x\n",
(val & link_status) >> USB_LINK_STATUS_SHIFT);
di->invalid_charger_detect_state = 2;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 57/57] power: ab8500_charger: Limit USB charger current

2012-09-25 Thread mathieu . poirier
From: Martin Bergstrom 

The USB charger current is limited according to information comming
from the USB driver

Signed-off-by: Martin Bergstrom 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index afb4fda..3c6f11c 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -1248,6 +1248,9 @@ static int ab8500_charger_set_vbus_in_curr(struct 
ab8500_charger *di,
if (di->max_usb_in_curr.set_max > 0)
min_value = min(di->max_usb_in_curr.set_max, min_value);
 
+   if (di->usb_state.usb_current >= 0)
+   min_value = min(di->usb_state.usb_current, min_value);
+
switch (min_value) {
case 100:
if (di->vbat < VBAT_TRESH_IP_CUR_RED)
@@ -3413,6 +3416,7 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
di->usb_chg.enabled = di->pdata->usb_enabled;
di->usb_chg.external = false;
+   di->usb_state.usb_current = -1;
 
/* Create a work queue for the charger */
di->charger_wq =
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 56/57] power: abx500_chargalg: Fix quick re-attach charger issue.

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

The patch for 426250 added a change to check for the quick
re-attachment of the charger connection as an error in the
AB8500 HW meant that a quick detach/attach wouldn't be
detected.
This patch isolates the original change so that newer AB's
are not affected.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Martin SJOBLOM 
Reviewed-by: Hakan BERG 
Reviewed-by: Jonas ABERG 
---
 drivers/power/abx500_chargalg.c |   11 ++-
 1 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index c8849af..7a81e4e 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1299,11 +1299,12 @@ static void abx500_chargalg_algorithm(struct 
abx500_chargalg *di)
abx500_chargalg_check_charger_voltage(di);
charger_status = abx500_chargalg_check_charger_connection(di);
 
-   ret = abx500_chargalg_check_charger_enable(di);
-   if (ret < 0)
-   dev_err(di->dev, "Checking charger if enabled error: %d line: 
%d\n",
-   ret, __LINE__);
-
+   if (is_ab8500(di->parent)) {
+   ret = abx500_chargalg_check_charger_enable(di);
+   if (ret < 0)
+   dev_err(di->dev, "Checking charger is enabled error");
+   dev_err(di->dev, ": Returned Value %d\n", ret);
+   }
/*
 * First check if we have a charger connected.
 * Also we don't allow charging of unknown batteries if configured
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 44/57] power: ab8500: remove unecesary define flag

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

Remove flag that serve no purpose from source code, Kconfig
and Makefile.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Hakan BERG 
Reviewed-by: Mian Yousaf KAUKAB 
---
 drivers/power/Kconfig  |7 ---
 drivers/power/ab8500_charger.c |2 +-
 2 files changed, 1 insertions(+), 8 deletions(-)

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index c1892f3..f7c13ae 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -303,13 +303,6 @@ config AB8500_BM
depends on AB8500_CORE && AB8500_GPADC
help
  Say Y to include support for AB8500 battery management.
-
-config AB8500_BATTERY_THERM_ON_BATCTRL
-   bool "Thermistor connected on BATCTRL ADC"
-   depends on AB8500_BM
-   help
- Say Y to enable battery temperature measurements using
- thermistor connected on BATCTRL ADC.
 endif # POWER_SUPPLY
 
 source "drivers/power/avs/Kconfig"
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 9449a33..d90fe9f 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -3369,7 +3369,7 @@ static int __devexit ab8500_charger_remove(struct 
platform_device *pdev)
flush_scheduled_work();
if (di->usb_chg.enabled)
power_supply_unregister(&di->usb_chg.psy);
-   if (di->ac_chg.enabled)
+   if (di->ac_chg.enabled && !di->ac_chg.external)
power_supply_unregister(&di->ac_chg.psy);
 
platform_set_drvdata(pdev, NULL);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 46/57] power: chargealg: Realign with upstream version

2012-09-25 Thread mathieu . poirier
From: Loic Pallardy 

Upstream version of AB charge algo has been reverted
during kernel 3.4 port.
This patch restore state by:
- renaming ab8500_chargal.c in abx500_chargal.c
- renaming function from ab8500 to abx500
- moving generic structure in "include/mfd/abx500.h"

Goal is to ease next code reversion and realignment
with mainline

Signed-off-by: Loic Pallardy 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Philippe LANGLAIS 
---
 drivers/power/ab8500_charger.c   |  166 +++---
 include/linux/mfd/abx500.h   |   10 ++-
 include/linux/mfd/abx500/ab8500-bm.h |5 +-
 3 files changed, 65 insertions(+), 116 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index d90fe9f..68a4128 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -79,6 +79,7 @@
 #define AB8500_USB_LINK_STATUS 0x78
 #define AB8505_USB_LINK_STATUS 0xF8
 #define AB8500_STD_HOST_SUSP   0x18
+#define USB_LINK_STATUS_SHIFT  3
 
 /* Watchdog timeout constant */
 #define WD_TIMER   0x30 /* 4min */
@@ -743,8 +744,7 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
dev_err(di->dev, "VBUS has collapsed\n");
ret = -ENXIO;
break;
-   }
-   if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   } else {
dev_dbg(di->dev, "USB Type - Charging not allowed\n");
di->max_usb_in_curr.usb_type_max =
USB_CH_IP_CUR_LVL_0P05;
@@ -799,30 +799,22 @@ static int ab8500_charger_read_usb_type(struct 
ab8500_charger *di)
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
-   if (is_ab8500(di->parent)) {
+   if (is_ab8500(di->parent))
ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
-   AB8500_USB_LINE_STAT_REG, &val);
-   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
-   ret = abx500_get_register_interruptible(di->dev,
-   AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
-   } else {
-   dev_err(di->dev, "%s unsupported analog baseband\n", __func__);
-   return -ENXIO;
-   }
+   AB8500_USB_LINE_STAT_REG, &val);
+   else
+   ret = abx500_get_register_interruptible(di->dev,
+   AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
 
/* get the USB type */
-   if (is_ab8500(di->parent)) {
-   val = (val & AB8500_USB_LINK_STATUS) >> 3;
-   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
-   val = (val & AB8505_USB_LINK_STATUS) >> 3;
-   } else {
-   dev_err(di->dev, "%s unsupported analog baseband\n", __func__);
-   return -ENXIO;
-   }
+   if (is_ab8500(di->parent))
+   val = (val & AB8500_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT;
+   else
+   val = (val & AB8505_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT;
ret = ab8500_charger_max_usb_curr(di,
(enum ab8500_charger_link_status) val);
 
@@ -858,17 +850,12 @@ static int ab8500_charger_detect_usb_type(struct 
ab8500_charger *di)
return ret;
}
 
-   if (is_ab8500(di->parent)) {
+   if (is_ab8500(di->parent))
ret = abx500_get_register_interruptible(di->dev,
AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
-   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   else
ret = abx500_get_register_interruptible(di->dev,
AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
-   } else {
-   dev_err(di->dev,
-"%s unsupported analog baseband\n", __func__);
-   return -ENXIO;
-   }
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
@@ -882,15 +869,12 @@ static int ab8500_charger_detect_usb_type(struct 
ab8500_charger *di)
 */
 
/* get the USB type */
-   if (is_ab8500(di->parent)) {
-   val = (val & AB8500_USB_LINK_STATUS) &

[PATCH 52/57] power: abx500_chargalg: Use hrtimer

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

Timers used for charging safety and maintenance must work even when
CPU is power collapsed. By using hrtimers with realtime clock, system
is able to trigger an alarm that wakes the CPU up and make it possible
to handle the event.

Allow a little slack of 5 minutes to the hrtimers to allow CPU to be
waked up in a more optimal power saving way. A 5 minute delay to
time out timers on hours does not impact on safety.

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Mian Yousaf KAUKAB 
---
 drivers/power/abx500_chargalg.c |   94 ++-
 1 files changed, 53 insertions(+), 41 deletions(-)

diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 636d970..c8849af 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) ST-Ericsson SA 2012
+ * Copyright (c) 2012 Sony Mobile Communications AB
  *
  * Charging algorithm driver for abx500 variants
  *
@@ -8,11 +9,13 @@
  * Johan Palsson 
  * Karl Komierowski 
  * Arun R Murthy 
+ * Imre Sunyi 
  */
 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -32,6 +35,12 @@
 /* End-of-charge criteria counter */
 #define EOC_COND_CNT   10
 
+/* One hour expressed in seconds */
+#define ONE_HOUR_IN_SECONDS3600
+
+/* Five minutes expressed in seconds */
+#define FIVE_MINUTES_IN_SECONDS300
+
 #define to_abx500_chargalg_device_info(x) container_of((x), \
struct abx500_chargalg, chargalg_psy);
 
@@ -245,8 +254,8 @@ struct abx500_chargalg {
struct delayed_work chargalg_periodic_work;
struct delayed_work chargalg_wd_work;
struct work_struct chargalg_work;
-   struct timer_list safety_timer;
-   struct timer_list maintenance_timer;
+   struct hrtimer safety_timer;
+   struct hrtimer maintenance_timer;
struct kobject chargalg_kobject;
 };
 
@@ -261,38 +270,47 @@ BLOCKING_NOTIFIER_HEAD(charger_notifier_list);
 
 /**
  * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
- * @data:  pointer to the abx500_chargalg structure
+ * @timer: pointer to the hrtimer structure
  *
  * This function gets called when the safety timer for the charger
  * expires
  */
-static void abx500_chargalg_safety_timer_expired(unsigned long data)
+static enum hrtimer_restart
+abx500_chargalg_safety_timer_expired(struct hrtimer *timer)
 {
-   struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+   struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
+   safety_timer);
dev_err(di->dev, "Safety timer expired\n");
di->events.safety_timer_expired = true;
 
/* Trigger execution of the algorithm instantly */
queue_work(di->chargalg_wq, &di->chargalg_work);
+
+   return HRTIMER_NORESTART;
 }
 
 /**
  * abx500_chargalg_maintenance_timer_expired() - Expiration of
  * the maintenance timer
- * @i: pointer to the abx500_chargalg structure
+ * @timer: pointer to the timer structure
  *
  * This function gets called when the maintenence timer
  * expires
  */
-static void abx500_chargalg_maintenance_timer_expired(unsigned long data)
+static enum hrtimer_restart
+abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer)
+
 {
 
-   struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+   struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
+   maintenance_timer);
dev_dbg(di->dev, "Maintenance timer expired\n");
di->events.maintenance_timer_expired = true;
 
/* Trigger execution of the algorithm instantly */
queue_work(di->chargalg_wq, &di->chargalg_work);
+
+   return HRTIMER_NORESTART;
 }
 
 /**
@@ -392,19 +410,16 @@ static int 
abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
  */
 static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
 {
-   unsigned long timer_expiration = 0;
+   /* Charger-dependent expiration time in hours*/
+   int timer_expiration = 0;
 
switch (di->chg_info.charger_type) {
case AC_CHG:
-   timer_expiration =
-   round_jiffies(jiffies +
-   (di->bat->main_safety_tmr_h * 3600 * HZ));
+   timer_expiration = di->bat->main_safety_tmr_h;
break;
 
case USB_CHG:
-   timer_expiration =
-   round_jiffies(jiffies +
-   (di->bat->usb_safety_tmr_h * 3600 * HZ));
+   timer_expiration = di->bat->usb_safety_tmr_h;
break;
 
default:
@@ -413,11 +428,10 @@ static void abx500_chargalg_start_safety_timer(struct 
a

[PATCH 55/57] power: ab8500_charger: Add UsbLineCtrl2 reference

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

When the state of USB Charge detection is changed then the calls
use a define for another register in other bank. This change
creates a new define for the correct register and removes the
magic numbers that are present.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Hakan BERG 
Reviewed-by: Jonas ABERG 

Conflicts:

drivers/power/ab8500_charger.c
---
 drivers/power/ab8500_charger.c   |   11 +--
 include/linux/mfd/abx500/ab8500-bm.h |1 +
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 7f8f362..afb4fda 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -51,6 +51,7 @@
 #define VBUS_DET_DBNC1 0x01
 #define OTP_ENABLE_WD  0x01
 #define DROP_COUNT_RESET   0x01
+#define USB_CH_DET 0x01
 
 #define MAIN_CH_INPUT_CURR_SHIFT   4
 #define VBUS_IN_CURR_LIM_SHIFT 4
@@ -2287,9 +2288,8 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
USB_CH_ENA, USB_CH_ENA);
/*Enable charger detection*/
abx500_mask_and_set_register_interruptible(di->dev,
-   AB8500_USB,
-   AB8500_MCH_IPT_CURLVL_REG,
-   0x01, 0x01);
+   AB8500_USB, AB8500_USB_LINE_CTRL2_REG,
+   USB_CH_DET, USB_CH_DET);
di->invalid_charger_detect_state = 1;
/*exit and wait for new link status interrupt.*/
return;
@@ -2300,9 +2300,8 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
"Invalid charger detected, state= 1\n");
/*Stop charger detection*/
abx500_mask_and_set_register_interruptible(di->dev,
-   AB8500_USB,
-   AB8500_MCH_IPT_CURLVL_REG,
-   0x01, 0x00);
+   AB8500_USB, AB8500_USB_LINE_CTRL2_REG,
+   USB_CH_DET, 0x00);
/*Check link status*/
if (is_ab8500(di->parent))
ret = abx500_get_register_interruptible(di->dev,
diff --git a/include/linux/mfd/abx500/ab8500-bm.h 
b/include/linux/mfd/abx500/ab8500-bm.h
index 721bd6d..6b69ad5 100644
--- a/include/linux/mfd/abx500/ab8500-bm.h
+++ b/include/linux/mfd/abx500/ab8500-bm.h
@@ -23,6 +23,7 @@
  * Bank : 0x5
  */
 #define AB8500_USB_LINE_STAT_REG   0x80
+#define AB8500_USB_LINE_CTRL2_REG  0x82
 #define AB8500_USB_LINK1_STAT_REG  0x94
 
 /*
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 53/57] power: ab8500_fg: Moving structure definitions to header file

2012-09-25 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

Signed-off-by: Mathieu Poirier 
---
 drivers/power/ab8500_fg.c |  196 +--
 drivers/power/ab8500_fg.h |  201 +
 2 files changed, 206 insertions(+), 191 deletions(-)
 create mode 100644 drivers/power/ab8500_fg.h

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 5b5c7ea..145c1f1 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -32,51 +32,7 @@
 #include 
 #include 
 #include 
-
-#define MILLI_TO_MICRO 1000
-#define FG_LSB_IN_MA   1627
-#define QLSB_NANO_AMP_HOURS_X101129
-#define INS_CURR_TIMEOUT   (3 * HZ)
-
-#define SEC_TO_SAMPLE(S)   (S * 4)
-
-#define NBR_AVG_SAMPLES20
-
-#define LOW_BAT_CHECK_INTERVAL (HZ / 16) /* 62.5 ms */
-
-#define VALID_CAPACITY_SEC (45 * 60) /* 45 minutes */
-#define BATT_OK_MIN2360 /* mV */
-#define BATT_OK_INCREMENT  50 /* mV */
-#define BATT_OK_MAX_NR_INCREMENTS  0xE
-
-/* FG constants */
-#define BATT_OVV   0x01
-
-#define interpolate(x, x1, y1, x2, y2) \
-   ((y1) + y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1;
-
-#define to_ab8500_fg_device_info(x) container_of((x), \
-   struct ab8500_fg, fg_psy);
-
-/**
- * struct ab8500_fg_interrupts - ab8500 fg interupts
- * @name:  name of the interrupt
- * @isrfunction pointer to the isr
- */
-struct ab8500_fg_interrupts {
-   char *name;
-   irqreturn_t (*isr)(int irq, void *data);
-};
-
-enum ab8500_fg_discharge_state {
-   AB8500_FG_DISCHARGE_INIT,
-   AB8500_FG_DISCHARGE_INITMEASURING,
-   AB8500_FG_DISCHARGE_INIT_RECOVERY,
-   AB8500_FG_DISCHARGE_RECOVERY,
-   AB8500_FG_DISCHARGE_READOUT_INIT,
-   AB8500_FG_DISCHARGE_READOUT,
-   AB8500_FG_DISCHARGE_WAKEUP,
-};
+#include "ab8500_fg.h"
 
 static char *discharge_state[] = {
"DISCHARGE_INIT",
@@ -87,159 +43,17 @@ static char *discharge_state[] = {
"DISCHARGE_READOUT",
"DISCHARGE_WAKEUP",
 };
-
-enum ab8500_fg_charge_state {
-   AB8500_FG_CHARGE_INIT,
-   AB8500_FG_CHARGE_READOUT,
-};
-
 static char *charge_state[] = {
"CHARGE_INIT",
"CHARGE_READOUT",
 };
 
-enum ab8500_fg_calibration_state {
-   AB8500_FG_CALIB_INIT,
-   AB8500_FG_CALIB_WAIT,
-   AB8500_FG_CALIB_END,
-};
-
-struct ab8500_fg_avg_cap {
-   int avg;
-   int samples[NBR_AVG_SAMPLES];
-   __kernel_time_t time_stamps[NBR_AVG_SAMPLES];
-   int pos;
-   int nbr_samples;
-   int sum;
-};
-
-struct ab8500_fg_cap_scaling {
-   bool enable;
-   int cap_to_scale[2];
-   int disable_cap_level;
-   int scaled_cap;
-};
-
-struct ab8500_fg_battery_capacity {
-   int max_mah_design;
-   int max_mah;
-   int mah;
-   int permille;
-   int level;
-   int prev_mah;
-   int prev_percent;
-   int prev_level;
-   int user_mah;
-   struct ab8500_fg_cap_scaling cap_scale;
-};
-
-struct ab8500_fg_flags {
-   bool fg_enabled;
-   bool conv_done;
-   bool charging;
-   bool fully_charged;
-   bool force_full;
-   bool low_bat_delay;
-   bool low_bat;
-   bool bat_ovv;
-   bool batt_unknown;
-   bool calibrate;
-   bool user_cap;
-   bool batt_id_received;
-};
+#define interpolate(x, x1, y1, x2, y2) \
+   ((y1) + y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1;
 
-struct inst_curr_result_list {
-   struct list_head list;
-   int *result;
-};
+#define to_ab8500_fg_device_info(x) container_of((x), \
+   struct ab8500_fg, fg_psy);
 
-/**
- * struct ab8500_fg - ab8500 FG device information
- * @dev:   Pointer to the structure device
- * @node:  a list of AB8500 FGs, hence prepared for reentrance
- * @irqholds the CCEOC interrupt number
- * @vbat:  Battery voltage in mV
- * @vbat_nom:  Nominal battery voltage in mV
- * @inst_curr: Instantenous battery current in mA
- * @avg_curr:  Average battery current in mA
- * @bat_temp   battery temperature
- * @fg_samples:Number of samples used in the FG accumulation
- * @accu_charge:   Accumulated charge from the last conversion
- * @recovery_cnt:  Counter for recovery mode
- * @high_curr_cnt: Counter for high current mode
- * @init_cnt:  Counter for init mode
- * @low_bat_cntCounter for number of consecutive low battery 
measures
- * @nbr_cceoc_irq_cnt  Counter for number of CCEOC irqs received since enabled
- * @recovery_needed:   Indicate if recovery is needed
- * @high_curr_mode:Indicate if we're in high current mode
- * @init_capacity: Indicate if initial capacity measuring should be

[PATCH 50/57] power: ab8500-chargalg: update battery health on safety timer exp

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

When the charging safety timer is elapsed the battery health is shown as "Good".
This is misleading and also hard to distingiush problems reported on "phone
discharges although charger is attached".

When safety timer elapses that is an indication of a fault in the battery of
some kind. Hence report as POWER_SUPPLY_HEALTH_UNSPEC_FAILURE.

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Arun MURTHY 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/abx500_chargalg.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 4db0ef0..1df238f 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1711,6 +1711,10 @@ static int abx500_chargalg_get_property(struct 
power_supply *psy,
val->intval = POWER_SUPPLY_HEALTH_COLD;
else
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+   } else if (di->charge_state == STATE_SAFETY_TIMER_EXPIRED ||
+   di->charge_state ==
+   STATE_SAFETY_TIMER_EXPIRED_INIT) {
+   val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
} else {
val->intval = POWER_SUPPLY_HEALTH_GOOD;
}
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 49/57] power: Cancelling status charging notification.

2012-09-25 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

Signed-off-by: Mathieu Poirier 
---
 drivers/power/abx500_chargalg.c |2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index ce58f20..4db0ef0 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -641,10 +641,8 @@ static void abx500_chargalg_hold_charging(struct 
abx500_chargalg *di)
abx500_chargalg_usb_en(di, false, 0, 0);
abx500_chargalg_stop_safety_timer(di);
abx500_chargalg_stop_maintenance_timer(di);
-   di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
di->maintenance_chg = false;
cancel_delayed_work(&di->chargalg_wd_work);
-   power_supply_changed(&di->chargalg_psy);
 }
 
 /**
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 48/57] power: ab8500 : quick re-attach for ext charger

2012-09-25 Thread mathieu . poirier
From: Rupesh Kumar 

Quick re-attach charging behaviour is not required
for external ac charger. Internal AC/USB Charger removal
detection problem is due to a bug in AB8500 ASICs.

Signed-off-by: Rupesh Kumar 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Hakan BERG 
Reviewed-by: Philippe LANGLAIS 
---
 drivers/power/abx500_chargalg.c |5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 180deab..ce58f20 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -330,12 +330,13 @@ static int abx500_chargalg_check_charger_enable(struct 
abx500_chargalg *di)
return di->usb_chg->ops.check_enable(di->usb_chg,
di->bat->bat_type[di->bat->batt_id].normal_vol_lvl,
di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
-   } else if (di->chg_info.charger_type & AC_CHG) {
+   } else if ((di->chg_info.charger_type & AC_CHG) &&
+   !(di->ac_chg->external)) {
return di->ac_chg->ops.check_enable(di->ac_chg,
di->bat->bat_type[di->bat->batt_id].normal_vol_lvl,
di->bat->bat_type[di->bat->batt_id].normal_cur_lvl);
}
-   return -ENXIO;
+   return 0;
 }
 
 /**
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 47/57] power: Harmonising platform data declaration/handling

2012-09-25 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

Making platform data declaration and handling similar accross all
ab8500_xyc.c battery management files.  Also adding gards against
NULL platform data.

Signed-off-by: Philippe Langlais 
Signed-off-by: Mathieu Poirier 
---
 drivers/power/ab8500_btemp.c|   17 +
 drivers/power/ab8500_charger.c  |   18 +-
 drivers/power/ab8500_fg.c   |   17 +
 drivers/power/abx500_chargalg.c |   25 -
 4 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 1f33122..cf4b653 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -1028,10 +1028,10 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
 {
int irq, i, ret = 0;
u8 val;
-   struct ab8500_platform_data *plat_data;
-   struct ab8500_btemp *di;
+   struct ab8500_platform_data *plat;
 
-   di = kzalloc(sizeof(*di), GFP_KERNEL);
+   struct ab8500_btemp *di =
+   kzalloc(sizeof(struct ab8500_btemp), GFP_KERNEL);
if (!di)
return -ENOMEM;
 
@@ -1042,22 +1042,23 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
 
di->initialized = false;
 
+   plat = dev_get_platdata(di->parent->dev);
+
/* get btemp specific platform data */
-   plat_data = dev_get_platdata(di->parent->dev);
-   di->pdata = plat_data->btemp;
-   if (!di->pdata) {
+   if (!plat || !plat->btemp) {
dev_err(di->dev, "no btemp platform data supplied\n");
ret = -EINVAL;
goto free_device_info;
}
+   di->pdata = plat->btemp;
 
/* get battery specific platform data */
-   di->bat = plat_data->battery;
-   if (!di->bat) {
+   if (!plat->battery) {
dev_err(di->dev, "no battery platform data supplied\n");
ret = -EINVAL;
goto free_device_info;
}
+   di->bat = plat->battery;
 
/* BTEMP supply */
di->btemp_psy.name = "ab8500_btemp";
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 68a4128..1290470 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -3319,10 +3319,10 @@ static int __devexit ab8500_charger_remove(struct 
platform_device *pdev)
 static int __devinit ab8500_charger_probe(struct platform_device *pdev)
 {
int irq, i, charger_status, ret = 0, ch_stat;
-   struct ab8500_platform_data *plat_data;
-   struct ab8500_charger *di;
+   struct ab8500_platform_data *plat;
 
-   di = kzalloc(sizeof(*di), GFP_KERNEL);
+   struct ab8500_charger *di =
+   kzalloc(sizeof(struct ab8500_charger), GFP_KERNEL);
if (!di)
return -ENOMEM;
 
@@ -3335,24 +3335,24 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
spin_lock_init(&di->usb_state.usb_lock);
mutex_init(&di->usb_ipt_crnt_lock);
 
-   /* get charger specific platform data */
-   plat_data = dev_get_platdata(di->parent->dev);
+   plat = dev_get_platdata(di->parent->dev);
 
-   di->pdata = plat_data->charger;
-   if (!di->pdata) {
+   /* get charger specific platform data */
+   if (!plat || !plat->charger) {
dev_err(di->dev, "no charger platform data supplied\n");
ret = -EINVAL;
goto free_device_info;
}
+   di->pdata = plat->charger;
 
/* get battery specific platform data */
-   di->bat = plat_data->battery;
-   if (!di->bat) {
+   if (!plat->battery) {
dev_err(di->dev, "no battery platform data supplied\n");
ret = -EINVAL;
goto free_device_info;
}
 
+   di->bat = plat->battery;
di->autopower = false;
di->invalid_charger_detect_state = 0;
 
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index cf6d2b5..5b5c7ea 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -3158,10 +3158,10 @@ static int __devinit ab8500_fg_probe(struct 
platform_device *pdev)
 {
int i, irq;
int ret = 0;
-   struct ab8500_platform_data *plat_data;
-   struct ab8500_fg *di;
+   struct ab8500_platform_data *plat;
 
-   di = kzalloc(sizeof(*di), GFP_KERNEL);
+   struct ab8500_fg *di =
+   kzalloc(sizeof(struct ab8500_fg), GFP_KERNEL);
if (!di)
return -ENOMEM;
 
@@ -3172,22 +3172,23 @@ static int __devinit ab8500_fg_probe(struct 
platform_device *pdev)
di->parent = dev_get_drvdata(pdev->dev.parent);
di->gpadc = ab8500_gpadc_ge

[PATCH 36/57] power: add backup battery charge voltages.

2012-09-25 Thread mathieu . poirier
From: Yang QU 

Add 2.7v, 2.9v, 3.0v, 3.2v and 3.3v charging voltage
for backup battery. Before that only 2.5v, 2.6v, 2.8v,
3.1v are available.

Signed-off-by: Yang QU 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Maxime COQUELIN 
Reviewed-by: Marcus COOPER 
Reviewed-by: Xiao Mei ZHANG 
---
 drivers/power/ab8500_charger.c   |9 +++--
 include/linux/mfd/abx500/ab8500-bm.h |   24 
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index b3b8f77..8137ea5 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2834,6 +2834,7 @@ static int ab8500_charger_usb_get_property(struct 
power_supply *psy,
 static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
 {
int ret = 0;
+   u8 bup_vch_range = 0, vbup33_vrtcn = 0;
 
/* Setup maximum charger current and voltage for ABB cut2.0 */
if (!is_ab8500_1p1_or_earlier(di->parent)) {
@@ -2935,11 +2936,15 @@ static int ab8500_charger_init_hw_registers(struct 
ab8500_charger *di)
}
 
/* Backup battery voltage and current */
+   if (di->bat->bkup_bat_v > BUP_VCH_SEL_3P1V)
+   bup_vch_range = BUP_VCH_RANGE;
+   if (di->bat->bkup_bat_v == BUP_VCH_SEL_3P3V)
+   vbup33_vrtcn = VBUP33_VRTCN;
+
ret = abx500_set_register_interruptible(di->dev,
AB8500_RTC,
AB8500_RTC_BACKUP_CHG_REG,
-   di->bat->bkup_bat_v |
-   di->bat->bkup_bat_i);
+   (di->bat->bkup_bat_v & 0x3) | di->bat->bkup_bat_i);
if (ret) {
dev_err(di->dev, "failed to setup backup battery charging\n");
goto out;
diff --git a/include/linux/mfd/abx500/ab8500-bm.h 
b/include/linux/mfd/abx500/ab8500-bm.h
index cd15ea3..5ae8a6f 100644
--- a/include/linux/mfd/abx500/ab8500-bm.h
+++ b/include/linux/mfd/abx500/ab8500-bm.h
@@ -105,6 +105,7 @@
 #define AB8500_RTC_BACKUP_CHG_REG  0x0C
 #define AB8500_RTC_CC_CONF_REG 0x01
 #define AB8500_RTC_CTRL_REG0x0B
+#define AB8500_RTC_CTRL1_REG   0x11
 
 /*
  * OTP register offsets
@@ -179,10 +180,25 @@
 #define BUP_ICH_SEL_300UA  0x08
 #define BUP_ICH_SEL_700UA  0x0C
 
-#define BUP_VCH_SEL_2P5V   0x00
-#define BUP_VCH_SEL_2P6V   0x01
-#define BUP_VCH_SEL_2P8V   0x02
-#define BUP_VCH_SEL_3P1V   0x03
+enum bup_vch_sel {
+   BUP_VCH_SEL_2P5V,
+   BUP_VCH_SEL_2P6V,
+   BUP_VCH_SEL_2P8V,
+   BUP_VCH_SEL_3P1V,
+   /*
+* Note that the following 5 values 2.7v, 2.9v, 3.0v, 3.2v, 3.3v
+* are only available on ab8540. You can't choose these 5
+* voltage on ab8500/ab8505/ab9540.
+*/
+   BUP_VCH_SEL_2P7V,
+   BUP_VCH_SEL_2P9V,
+   BUP_VCH_SEL_3P0V,
+   BUP_VCH_SEL_3P2V,
+   BUP_VCH_SEL_3P3V,
+};
+
+#define BUP_VCH_RANGE  0x02
+#define VBUP33_VRTCN   0x01
 
 /* Battery OVV constants */
 #define BATT_OVV_ENA   0x02
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 45/57] power: ab8500: defer btemp filtering while init

2012-09-25 Thread mathieu . poirier
From: Rupesh Kumar 

Due to btemp filtering enabled during init, temp values
reported to charge algorithm driver started from 0.
As a result,charge algorithm was going into wrong
state and charging was stopped.
This patch defers btemp filtering till init is done.

Signed-off-by: Rupesh Kumar 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Martin SJOBLOM 
Reviewed-by: Philippe LANGLAIS 
---
 drivers/power/ab8500_btemp.c |6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index b24835f..1f33122 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -613,7 +613,6 @@ static void ab8500_btemp_periodic_work(struct work_struct 
*work)
struct ab8500_btemp, btemp_periodic_work.work);
 
if (!di->initialized) {
-   di->initialized = true;
/* Identify the battery */
if (ab8500_btemp_id(di) < 0)
dev_warn(di->dev, "failed to identify the battery\n");
@@ -626,8 +625,9 @@ static void ab8500_btemp_periodic_work(struct work_struct 
*work)
 * same temperature. Else only allow 1 degree change from previous
 * reported value in the direction of the new measurement.
 */
-   if (bat_temp == di->prev_bat_temp || !di->initialized) {
-   if (di->bat_temp != di->prev_bat_temp || !di->initialized) {
+   if ((bat_temp == di->prev_bat_temp) || !di->initialized) {
+   if ((di->bat_temp != di->prev_bat_temp) || !di->initialized) {
+   di->initialized = true;
di->bat_temp = bat_temp;
power_supply_changed(&di->btemp_psy);
}
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 27/57] power: sysfs interface update

2012-09-25 Thread mathieu . poirier
From: Michel JAOUEN 

Add new sysfs interface to get current charge status

Signed-off-by: Michel JAOUEN 
Signed-off-by: Loic Pallardy 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Olivier CLERGEAUD 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c  |3 +++
 drivers/power/abx500_chargalg.c |   24 +++-
 2 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 4129599..0a781a0 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2759,6 +2759,9 @@ static int ab8500_charger_usb_notifier_call(struct 
notifier_block *nb,
enum ab8500_usb_state bm_usb_state;
unsigned mA = *((unsigned *)power);
 
+   if (di == NULL)
+   return NOTIFY_DONE;
+
if (event != USB_EVENT_VBUS) {
dev_dbg(di->dev, "not a standard host, returning\n");
return NOTIFY_DONE;
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index d3efc2a..4e3d20f 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1679,6 +1679,27 @@ static int abx500_chargalg_get_property(struct 
power_supply *psy,
return 0;
 }
 
+/**
+ * abx500_chargalg_sysfs_show() - sysfs show operations
+ * @kobj:  pointer to the struct kobject
+ * @attr:  pointer to the struct attribute
+ * @buf:   buffer that holds the parameter to send to userspace
+ *
+ * Returns a buffer to be displayed in user space
+ */
+static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
+   struct attribute *attr, char *buf)
+{
+   struct abx500_chargalg *di = container_of(kobj,
+   struct abx500_chargalg, chargalg_kobject);
+
+   if ((di->susp_status.ac_suspended == true) &&
+   (di->susp_status.usb_suspended == true))
+   return sprintf(buf, "0\n");
+   else
+   return sprintf(buf, "1\n");
+}
+
 /* Exposure to the sysfs interface */
 
 /**
@@ -1749,7 +1770,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct 
kobject *kobj,
 static struct attribute abx500_chargalg_en_charger = \
 {
.name = "chargalg",
-   .mode = S_IWUGO,
+   .mode = S_IRUGO | S_IWUSR,
 };
 
 static struct attribute *abx500_chargalg_chg[] = {
@@ -1758,6 +1779,7 @@ static struct attribute *abx500_chargalg_chg[] = {
 };
 
 static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
+   .show = abx500_chargalg_sysfs_show,
.store = abx500_chargalg_sysfs_charger,
 };
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 29/57] power: ab8500_fg: Goto INIT_RECOVERY when charger removed

2012-09-25 Thread mathieu . poirier
From: Martin Bergström 

When the charger is removed we need to go to INIT_RECOVERY
state instead of directly to RECOVERY state.

Signed-off-by: Martin Bergstrom 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 861927d..e7a0e1f 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -1644,7 +1644,7 @@ static void ab8500_fg_algorithm_discharging(struct 
ab8500_fg *di)
 
if (di->recovery_needed) {
ab8500_fg_discharge_state_to(di,
-   AB8500_FG_DISCHARGE_RECOVERY);
+   AB8500_FG_DISCHARGE_INIT_RECOVERY);
 
queue_delayed_work(di->fg_wq,
&di->fg_periodic_work, 0);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 37/57] power: ab8500_bm: Quick re-attach charging behaviour

2012-09-25 Thread mathieu . poirier
From: Kalle Komierowski 

Due to a bug in some AB8500 ASICs charger removal cannot always
be detected if the removal and reinsertion is done to close in time.
This patch detects above described case and handles the situation
so that charging will be kept turned on.

Signed-off-by: Kalle Komierowski 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Jonas ABERG 
Reviewed-by: Philippe LANGLAIS 
---
 drivers/power/ab8500_charger.c|  105 -
 drivers/power/abx500_chargalg.c   |   31 -
 include/linux/mfd/abx500/ux500_chargalg.h |1 +
 3 files changed, 134 insertions(+), 3 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 8137ea5..70e7c5e 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -49,6 +49,7 @@
 #define VBUS_DET_DBNC100   0x02
 #define VBUS_DET_DBNC1 0x01
 #define OTP_ENABLE_WD  0x01
+#define DROP_COUNT_RESET   0x01
 
 #define MAIN_CH_INPUT_CURR_SHIFT   4
 #define VBUS_IN_CURR_LIM_SHIFT 4
@@ -1672,6 +1673,105 @@ static int ab8500_charger_usb_en(struct ux500_charger 
*charger,
 }
 
 /**
+ * ab8500_charger_usb_check_enable() - enable usb charging
+ * @charger:   pointer to the ux500_charger structure
+ * @vset:  charging voltage
+ * @iset:  charger output current
+ *
+ * Check if the VBUS charger has been disconnected and reconnected without
+ * AB8500 rising an interrupt. Returns 0 on success.
+ */
+static int ab8500_charger_usb_check_enable(struct ux500_charger *charger,
+   int vset, int iset)
+{
+   u8 usbch_ctrl1 = 0;
+   int ret = 0;
+
+   struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
+
+   if (!di->usb.charger_connected)
+   return ret;
+
+   ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+   AB8500_USBCH_CTRL1_REG, &usbch_ctrl1);
+   if (ret < 0) {
+   dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+   return ret;
+   }
+   dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1);
+
+   if (!(usbch_ctrl1 & USB_CH_ENA)) {
+   dev_info(di->dev, "Charging has been disabled abnormally and 
will be re-enabled\n");
+
+   ret = abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_CHARGER, AB8500_CHARGER_CTRL,
+   DROP_COUNT_RESET, DROP_COUNT_RESET);
+   if (ret < 0) {
+   dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
+   return ret;
+   }
+
+   ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset);
+   if (ret < 0) {
+   dev_err(di->dev, "Failed to enable VBUS charger %d\n",
+   __LINE__);
+   return ret;
+   }
+   }
+   return ret;
+}
+
+/**
+ * ab8500_charger_ac_check_enable() - enable usb charging
+ * @charger:   pointer to the ux500_charger structure
+ * @vset:  charging voltage
+ * @iset:  charger output current
+ *
+ * Check if the AC charger has been disconnected and reconnected without
+ * AB8500 rising an interrupt. Returns 0 on success.
+ */
+static int ab8500_charger_ac_check_enable(struct ux500_charger *charger,
+   int vset, int iset)
+{
+   u8 mainch_ctrl1 = 0;
+   int ret = 0;
+
+   struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
+
+   if (!di->ac.charger_connected)
+   return ret;
+
+   ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+   AB8500_MCH_CTRL1, &mainch_ctrl1);
+   if (ret < 0) {
+   dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+   return ret;
+   }
+   dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1);
+
+   if (!(mainch_ctrl1 & MAIN_CH_ENA)) {
+   dev_info(di->dev, "Charging has been disabled abnormally and 
will be re-enabled\n");
+
+   ret = abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_CHARGER, AB8500_CHARGER_CTRL,
+   DROP_COUNT_RESET, DROP_COUNT_RESET);
+
+   if (ret < 0) {
+   dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
+   return ret;
+   }
+
+   ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset);
+   if (ret < 0) {
+   dev_err(di->dev, "failed to enable AC charger %d\n",
+  

[PATCH 43/57] power: charging: Add AB8505_USB_LINK_STATUS

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

The ab8505 does not have the same address for USB link-status
as has ab8500. Add AB8505_USB_LINK_STATUS and code to switch
to correct constant.

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Mian Yousaf KAUKAB 
Reviewed-by: Marcus COOPER 
Reviewed-by: Rabin VINCENT 
---
 drivers/power/ab8500_charger.c |   46 ---
 1 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 18931e4..9449a33 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -77,6 +77,7 @@
 
 /* UsbLineStatus register bit masks */
 #define AB8500_USB_LINK_STATUS 0x78
+#define AB8505_USB_LINK_STATUS 0xF8
 #define AB8500_STD_HOST_SUSP   0x18
 
 /* Watchdog timeout constant */
@@ -801,10 +802,12 @@ static int ab8500_charger_read_usb_type(struct 
ab8500_charger *di)
if (is_ab8500(di->parent)) {
ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
AB8500_USB_LINE_STAT_REG, &val);
-   } else {
-   if (is_ab9540(di->parent) || is_ab8505(di->parent))
+   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
ret = abx500_get_register_interruptible(di->dev,
AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
+   } else {
+   dev_err(di->dev, "%s unsupported analog baseband\n", __func__);
+   return -ENXIO;
}
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
@@ -812,7 +815,14 @@ static int ab8500_charger_read_usb_type(struct 
ab8500_charger *di)
}
 
/* get the USB type */
-   val = (val & AB8500_USB_LINK_STATUS) >> 3;
+   if (is_ab8500(di->parent)) {
+   val = (val & AB8500_USB_LINK_STATUS) >> 3;
+   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   val = (val & AB8505_USB_LINK_STATUS) >> 3;
+   } else {
+   dev_err(di->dev, "%s unsupported analog baseband\n", __func__);
+   return -ENXIO;
+   }
ret = ab8500_charger_max_usb_curr(di,
(enum ab8500_charger_link_status) val);
 
@@ -848,12 +858,17 @@ static int ab8500_charger_detect_usb_type(struct 
ab8500_charger *di)
return ret;
}
 
-   if (is_ab8500(di->parent))
+   if (is_ab8500(di->parent)) {
ret = abx500_get_register_interruptible(di->dev,
AB8500_USB, AB8500_USB_LINE_STAT_REG, &val);
-   else
+   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
ret = abx500_get_register_interruptible(di->dev,
AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
+   } else {
+   dev_err(di->dev,
+"%s unsupported analog baseband\n", __func__);
+   return -ENXIO;
+   }
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
@@ -867,7 +882,15 @@ static int ab8500_charger_detect_usb_type(struct 
ab8500_charger *di)
 */
 
/* get the USB type */
-   val = (val & AB8500_USB_LINK_STATUS) >> 3;
+   if (is_ab8500(di->parent)) {
+   val = (val & AB8500_USB_LINK_STATUS) >> 3;
+   } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   val = (val & AB8505_USB_LINK_STATUS) >> 3;
+   } else {
+   dev_err(di->dev,
+"%s unsupported analog baseband\n", __func__);
+   return -ENXIO;
+   }
if (val)
break;
}
@@ -2277,6 +2300,7 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
int detected_chargers;
int ret;
u8 val;
+   u8 link_status;
 
struct ab8500_charger *di = container_of(work,
struct ab8500_charger, usb_link_status_work);
@@ -2303,9 +2327,13 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
else
dev_dbg(di->dev, "Error reading USB link status\n");
 
+   if (is_ab9540(di->parent) || is_ab8505(di->parent))
+   link_status = AB8505_USB_LINK_STATUS;
+   else
+   link_status = AB8500_USB_LINK_STATUS;
+
if (detected_chargers & USB_PW_CONN) {
-  

[PATCH 42/57] power: charging: Allow capacity to raise from 1%

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

When battery capacity was going below 1% fg in not supposed
to report 0% unless we've got the LOW_BAT IRQ, no matter
what the FG-algorithm says. This made fg get stuck at 1% if
charger is connected when capacity is 1%.
That problem is addressed with this patch.

Signed-off-by: Hakan BERG 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Srinidhi KASAGAR 
---
 drivers/power/ab8500_fg.c |6 ++
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index c5732e7..cf6d2b5 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -1357,9 +1357,6 @@ static void ab8500_fg_check_capacity_limits(struct 
ab8500_fg *di, bool init)
 * algorithm says.
 */
di->bat_cap.prev_percent = 1;
-   di->bat_cap.permille = 1;
-   di->bat_cap.prev_mah = 1;
-   di->bat_cap.mah = 1;
percent = 1;
 
changed = true;
@@ -1771,9 +1768,10 @@ static void ab8500_fg_algorithm(struct ab8500_fg *di)
ab8500_fg_algorithm_discharging(di);
}
 
-   dev_dbg(di->dev, "[FG_DATA] %d %d %d %d %d %d %d %d %d "
+   dev_dbg(di->dev, "[FG_DATA] %d %d %d %d %d %d %d %d %d %d "
"%d %d %d %d %d %d %d\n",
di->bat_cap.max_mah_design,
+   di->bat_cap.max_mah,
di->bat_cap.mah,
di->bat_cap.permille,
di->bat_cap.level,
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 41/57] power: ab8500_btemp: Filter btemp readings

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

Battery tempreature readings sometimes fails and results in
a value far from recent values. This patch adds a software
filter that disposes such readings, by allowing direct
updates on temperature only if two samples result in the
same temperature. Else only allow 1 degree change from previous
reported value in the direction of the new measurement.

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Martin SJOBLOM 
Reviewed-by: Rabin VINCENT 
---
 drivers/power/ab8500_btemp.c |   27 +--
 1 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 56a3bb9..b24835f 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -74,8 +74,8 @@ struct ab8500_btemp_ranges {
  * @dev:   Pointer to the structure device
  * @node:  List of AB8500 BTEMPs, hence prepared for reentrance
  * @curr_source:   What current source we use, in uA
- * @bat_temp:  Battery temperature in degree Celcius
- * @prev_bat_temp  Last dispatched battery temperature
+ * @bat_temp:  Dispatched battery temperature in degree Celcius
+ * @prev_bat_temp  Last measured battery temperature in degree Celcius
  * @parent:Pointer to the struct ab8500
  * @gpadc: Pointer to the struct gpadc
  * @fg:Pointer to the struct fg
@@ -608,6 +608,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
 static void ab8500_btemp_periodic_work(struct work_struct *work)
 {
int interval;
+   int bat_temp;
struct ab8500_btemp *di = container_of(work,
struct ab8500_btemp, btemp_periodic_work.work);
 
@@ -618,12 +619,26 @@ static void ab8500_btemp_periodic_work(struct work_struct 
*work)
dev_warn(di->dev, "failed to identify the battery\n");
}
 
-   di->bat_temp = ab8500_btemp_measure_temp(di);
-
-   if (di->bat_temp != di->prev_bat_temp) {
-   di->prev_bat_temp = di->bat_temp;
+   bat_temp = ab8500_btemp_measure_temp(di);
+   /*
+* Filter battery temperature.
+* Allow direct updates on temperature only if two samples result in
+* same temperature. Else only allow 1 degree change from previous
+* reported value in the direction of the new measurement.
+*/
+   if (bat_temp == di->prev_bat_temp || !di->initialized) {
+   if (di->bat_temp != di->prev_bat_temp || !di->initialized) {
+   di->bat_temp = bat_temp;
+   power_supply_changed(&di->btemp_psy);
+   }
+   } else if (bat_temp < di->prev_bat_temp) {
+   di->bat_temp--;
+   power_supply_changed(&di->btemp_psy);
+   } else if (bat_temp > di->prev_bat_temp) {
+   di->bat_temp++;
power_supply_changed(&di->btemp_psy);
}
+   di->prev_bat_temp = bat_temp;
 
if (di->events.ac_conn || di->events.usb_conn)
interval = di->bat->temp_interval_chg;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 40/57] power: ab8500: ADC for battery thermistor

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

When using ABx500_ADC_THERM_BATCTRL the battery ID resistor
is combined with a NTC resistor to both identify the battery and
to measure its temperature.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Mian Yousaf KAUKAB 
Reviewed-by: Michel JAOUEN 
Reviewed-by: Hakan BERG 
Reviewed-by: Rabin VINCENT 
---
 drivers/power/ab8500_btemp.c |4 +++-
 include/linux/mfd/abx500.h   |2 ++
 2 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 506f124..56a3bb9 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -557,7 +557,9 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
/* BATTERY_UNKNOWN is defined on position 0, skip it! */
for (i = BATTERY_UNKNOWN + 1; i < di->bat->n_btypes; i++) {
if ((res <= di->bat->bat_type[i].resis_high) &&
-   (res >= di->bat->bat_type[i].resis_low)) {
+   (res >= di->bat->bat_type[i].resis_low) &&
+   (di->bat->bat_type[i].adc_therm ==
+   di->bat->adc_therm)) {
dev_dbg(di->dev, "Battery detected on %s"
" low %d < res %d < high: %d"
" index: %d\n",
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 97e918f..cb2b82a 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -270,6 +270,7 @@ struct abx500_maxim_parameters {
  * @low_high_cur_lvl:  charger current in temp low/high state in mA
  * @low_high_vol_lvl:  charger voltage in temp low/high state in mV'
  * @battery_resistance:battery inner resistance in mOhm.
+ * @adc_therm: battery uses controller or resistor for temp.
  * @n_r_t_tbl_elements:number of elements in r_to_t_tbl
  * @r_to_t_tbl:table containing resistance to temp 
points
  * @n_v_cap_tbl_elements:  number of elements in v_to_cap_tbl
@@ -297,6 +298,7 @@ struct abx500_battery_type {
int low_high_cur_lvl;
int low_high_vol_lvl;
int battery_resistance;
+   enum abx500_adc_therm adc_therm;
int n_temp_tbl_elements;
struct abx500_res_to_temp *r_to_t_tbl;
int n_v_cap_tbl_elements;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 39/57] power: ab8500_charger: Prevent auto drop of VBUS

2012-09-25 Thread mathieu . poirier
From: Martin Sjoblom 

Do not set higher current in stepping functionality if VBUS is dropping.
After VBUS has dropped try to set current once again. If dropping again
then we have found the maximum capability of the charger.

Signed-off-by: Martin Sjoblom 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Per FORLIN 
---
 drivers/power/ab8500_charger.c |  166 
 1 files changed, 117 insertions(+), 49 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index ebeb068..18931e4 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -55,6 +55,7 @@
 #define MAIN_CH_INPUT_CURR_SHIFT   4
 #define VBUS_IN_CURR_LIM_SHIFT 4
 #define AUTO_VBUS_IN_CURR_LIM_SHIFT4
+#define VBUS_IN_CURR_LIM_RETRY_SET_TIME30 /* seconds */
 
 #define LED_INDICATOR_PWM_ENA  0x01
 #define LED_INDICATOR_PWM_DIS  0x00
@@ -199,10 +200,15 @@ struct ab8500_charger_usb_state {
spinlock_t usb_lock;
 };
 
+struct ab8500_charger_max_usb_in_curr {
+   int usb_type_max;
+   int set_max;
+   int calculated_max;
+};
+
 /**
  * struct ab8500_charger - ab8500 Charger device information
  * @dev:   Pointer to the structure device
- * @max_usb_in_curr:   Max USB charger input current
  * @vbus_detected: VBUS detected
  * @vbus_detected_start:
  * VBUS detected during startup
@@ -227,6 +233,7 @@ struct ab8500_charger_usb_state {
  * @bat:   Pointer to the abx500_bm platform data
  * @flags: Structure for information about events triggered
  * @usb_state: Structure for usb stack information
+ * @max_usb_in_curr:   Max USB charger input current
  * @ac_chg:AC charger power supply
  * @usb_chg:   USB charger power supply
  * @ac:Structure that holds the AC charger properties
@@ -255,7 +262,6 @@ struct ab8500_charger_usb_state {
  */
 struct ab8500_charger {
struct device *dev;
-   int max_usb_in_curr;
bool vbus_detected;
bool vbus_detected_start;
bool ac_conn;
@@ -266,7 +272,6 @@ struct ab8500_charger {
bool usb_device_is_unrecognised;
bool autopower;
int invalid_charger_detect_state;
-   bool is_usb_host;
int is_aca_rid;
atomic_t current_stepping_sessions;
struct ab8500 *parent;
@@ -275,6 +280,7 @@ struct ab8500_charger {
struct abx500_bm_data *bat;
struct ab8500_charger_event_flags flags;
struct ab8500_charger_usb_state usb_state;
+   struct ab8500_charger_max_usb_in_curr max_usb_in_curr;
struct ux500_charger ac_chg;
struct ux500_charger usb_chg;
struct ab8500_charger_info ac;
@@ -416,6 +422,10 @@ static void ab8500_charger_set_usb_connected(struct 
ab8500_charger *di,
if (connected != di->usb.charger_connected) {
dev_dbg(di->dev, "USB connected:%i\n", connected);
di->usb.charger_connected = connected;
+
+   if (!connected)
+   di->flags.vbus_drop_end = false;
+
sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present");
 
if (connected) {
@@ -665,23 +675,19 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
case USB_STAT_STD_HOST_C_S:
dev_dbg(di->dev, "USB Type - Standard host is ");
dev_dbg(di->dev, "detected through USB driver\n");
-   di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
-   di->is_usb_host = true;
+   di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_HOST_CHG_HS_CHIRP:
-   di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
-   di->is_usb_host = true;
+   di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_HOST_CHG_HS:
-   di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
-   di->is_usb_host = true;
+   di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_C_HS:
-   di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9;
-   di->is_usb_host = false;
+   di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P9;
di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_A:
@@ -690,8 +696,7 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
 * can consume (900mA). Closest level is 500mA
 */
dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n");
-   di-&g

[PATCH 38/57] power: l9540: Charge only mode fixes

2012-09-25 Thread mathieu . poirier
From: Rupesh Kumar 

Fix for: charging not getting enabled in
charge only mode by external charger.

Signed-off-by: Rupesh Kumar 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Michel JAOUEN 
Reviewed-by: Philippe LANGLAIS 
Reviewed-by: Philippe LANGLAIS 
---
 drivers/power/ab8500_charger.c|   42 +
 drivers/power/abx500_chargalg.c   |   14 +
 include/linux/mfd/abx500/ux500_chargalg.h |2 +
 3 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 70e7c5e..ebeb068 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -94,6 +95,10 @@
 #define AB8500_SW_CONTROL_FALLBACK 0x03
 /* Wait for enumeration before charging in us */
 #define WAIT_ACA_RID_ENUMERATION   (5 * 1000)
+/*External charger control*/
+#define AB8500_SYS_CHARGER_CONTROL_REG 0x52
+#define EXTERNAL_CHARGER_DISABLE_REG_VAL   0x03
+#define EXTERNAL_CHARGER_ENABLE_REG_VAL0x07
 
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
@@ -1672,6 +1677,29 @@ static int ab8500_charger_usb_en(struct ux500_charger 
*charger,
return ret;
 }
 
+static int ab8500_external_charger_prepare(struct notifier_block *charger_nb,
+   unsigned long event, void *data)
+{
+   int ret;
+   struct device *dev = data;
+   /*Toggle External charger control pin*/
+   ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
+ AB8500_SYS_CHARGER_CONTROL_REG,
+ EXTERNAL_CHARGER_DISABLE_REG_VAL);
+   if (ret < 0) {
+   dev_err(dev, "write reg failed %d\n", ret);
+   goto out;
+   }
+   ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
+ AB8500_SYS_CHARGER_CONTROL_REG,
+ EXTERNAL_CHARGER_ENABLE_REG_VAL);
+   if (ret < 0)
+   dev_err(dev, "Write reg failed %d\n", ret);
+
+out:
+   return ret;
+}
+
 /**
  * ab8500_charger_usb_check_enable() - enable usb charging
  * @charger:   pointer to the ux500_charger structure
@@ -3201,6 +3229,10 @@ static int ab8500_charger_suspend(struct platform_device 
*pdev,
 #define ab8500_charger_resume  NULL
 #endif
 
+static struct notifier_block charger_nb = {
+   .notifier_call = ab8500_external_charger_prepare,
+};
+
 static int __devexit ab8500_charger_remove(struct platform_device *pdev)
 {
struct ab8500_charger *di = platform_get_drvdata(pdev);
@@ -3233,6 +3265,11 @@ static int __devexit ab8500_charger_remove(struct 
platform_device *pdev)
/* Delete the work queue */
destroy_workqueue(di->charger_wq);
 
+   /*Unregister external charger enable notifier*/
+   if (!di->ac_chg.enabled)
+   blocking_notifier_chain_unregister(
+   &charger_notifier_list, &charger_nb);
+
flush_scheduled_work();
if (di->usb_chg.enabled)
power_supply_unregister(&di->usb_chg.psy);
@@ -3307,6 +3344,11 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
di->ac_chg.enabled = di->pdata->ac_enabled;
di->ac_chg.external = false;
 
+   /*notifier for external charger enabling*/
+   if (!di->ac_chg.enabled)
+   blocking_notifier_chain_register(
+   &charger_notifier_list, &charger_nb);
+
/* USB supply */
/* power_supply base class */
di->usb_chg.psy.name = "ab8500_usb";
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 9568f63..3ca00dd 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /* Watchdog kick interval */
 #define CHG_WD_INTERVAL(6 * HZ)
@@ -255,6 +256,9 @@ static enum power_supply_property abx500_chargalg_props[] = 
{
POWER_SUPPLY_PROP_HEALTH,
 };
 
+/*External charger prepare notifier*/
+BLOCKING_NOTIFIER_HEAD(charger_notifier_list);
+
 /**
  * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
  * @data:  pointer to the abx500_chargalg structure
@@ -508,6 +512,8 @@ static int abx500_chargalg_kick_watchdog(struct 
abx500_chargalg *di)
 static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
int vset, int iset)
 {
+   static int ab8500_chargalg_ex_ac_enable_toggle;
+
if (!di->ac_chg || !di->ac_chg->ops.enable)
return -ENXIO;
 
@@ -520,6 +526,14 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg 
*di, int enable,
  

[PATCH 35/57] power: ab8500_fg: Report unscaled capacity

2012-09-25 Thread mathieu . poirier
From: Martin Bergstrom 

Unscaled capacity should be reported for POWER_SUPPLY_PROP_CAPACITY.

Signed-off-by: Martin Bergstrom 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |6 ++
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index fde189a..c5732e7 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2159,9 +2159,7 @@ static int ab8500_fg_get_property(struct power_supply 
*psy,
val->intval = di->bat_cap.prev_mah;
break;
case POWER_SUPPLY_PROP_CAPACITY:
-   if (di->bat->capacity_scaling)
-   val->intval = di->bat_cap.cap_scale.scaled_cap;
-   else if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
+   if (di->flags.batt_unknown && !di->bat->chg_unknown_bat &&
di->flags.batt_id_received)
val->intval = 100;
else
@@ -2625,7 +2623,7 @@ static ssize_t ab8500_show_capacity(struct device *dev,
if (di->bat->capacity_scaling)
capacity = di->bat_cap.cap_scale.scaled_cap;
else
-   capacity = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
+   capacity = di->bat_cap.prev_percent;
 
return scnprintf(buf, PAGE_SIZE, "%d\n", capacity);
 }
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 33/57] power: u8500_charger: Delay for USB enumeration

2012-09-25 Thread mathieu . poirier
From: Paer-Olof Haakansson 

If charging is started before USB enumeration of an
Accessory Charger Adapter has finished, the AB8500 will
generate a VBUS_ERROR. This in turn results in timeouts
and delays the enumeration with around 15 seconds.
This patch delays the charging and then ramps currents
slowly to avoid VBUS errors. The delay allows the enumeration
to have finished before charging is turned on.

Signed-off-by: Martin Sjoblom 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/mfd/ab8500-core.c  |6 +
 drivers/power/ab8500_charger.c |  435 +--
 2 files changed, 329 insertions(+), 112 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 47adf80..ef13fe1 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -786,6 +786,12 @@ static struct resource __devinitdata 
ab8500_charger_resources[] = {
.end = AB8500_INT_CH_WD_EXP,
.flags = IORESOURCE_IRQ,
},
+   {
+   .name = "VBUS_CH_DROP_END",
+   .start = AB8500_INT_VBUS_CH_DROP_END,
+   .end = AB8500_INT_VBUS_CH_DROP_END,
+   .flags = IORESOURCE_IRQ,
+   },
 };
 
 static struct resource __devinitdata ab8500_btemp_resources[] = {
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 2a323cf..b3b8f77 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -52,6 +52,7 @@
 
 #define MAIN_CH_INPUT_CURR_SHIFT   4
 #define VBUS_IN_CURR_LIM_SHIFT 4
+#define AUTO_VBUS_IN_CURR_LIM_SHIFT4
 
 #define LED_INDICATOR_PWM_ENA  0x01
 #define LED_INDICATOR_PWM_DIS  0x00
@@ -85,14 +86,13 @@
 /* Step up/down delay in us */
 #define STEP_UDELAY1000
 
-/* Wait for enumeration before charging in ms */
-#define WAIT_FOR_USB_ENUMERATION   (5 * 1000)
-
 #define CHARGER_STATUS_POLL 10 /* in ms */
 
 #define CHG_WD_INTERVAL(60 * HZ)
 
 #define AB8500_SW_CONTROL_FALLBACK 0x03
+/* Wait for enumeration before charging in us */
+#define WAIT_ACA_RID_ENUMERATION   (5 * 1000)
 
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
@@ -182,12 +182,14 @@ struct ab8500_charger_event_flags {
bool usbchargernotok;
bool chgwdexp;
bool vbus_collapse;
+   bool vbus_drop_end;
 };
 
 struct ab8500_charger_usb_state {
-   bool usb_changed;
int usb_current;
+   int usb_current_tmp;
enum ab8500_usb_state state;
+   enum ab8500_usb_state state_tmp;
spinlock_t usb_lock;
 };
 
@@ -207,6 +209,11 @@ struct ab8500_charger_usb_state {
  * @old_vbat   Previously measured battery voltage
  * @usb_device_is_unrecognised USB device is unrecognised by the hardware
  * @autopower  Indicate if we should have automatic pwron after pwrloss
+ * @invalid_charger_detect_state:
+   State when forcing AB to use invalid charger
+ * @is_aca_rid:Incicate if accessory is ACA type
+ * @current_stepping_sessions:
+ * Counter for current stepping sessions
  * @invalid_charger_detect_state   State when forcing AB to use invalid 
charger
  * @parent:Pointer to the struct ab8500
  * @gpadc: Pointer to the struct gpadc
@@ -225,7 +232,6 @@ struct ab8500_charger_usb_state {
  * @check_usbchgnotok_work:Work for checking USB charger not ok status
  * @kick_wd_work:  Work for kicking the charger watchdog in case
  * of ABB rev 1.* due to the watchog logic bug
- * @attach_work:   Work for checking the usb enumeration
  * @ac_charger_attached_work:  Work for checking if AC charger is still
  * connected
  * @usb_charger_attached_work: Work for checking if USB charger is still
@@ -234,6 +240,8 @@ struct ab8500_charger_usb_state {
  * @detect_usb_type_work:  Work for detecting the USB type connected
  * @usb_link_status_work:  Work for checking the new USB link status
  * @usb_state_changed_work:Work for checking USB state
+ * @attach_work:   Work for detecting USB type
+ * @vbus_drop_end_work:Work for detecting VBUS drop end
  * @check_main_thermal_prot_work:
  * Work for checking Main thermal status
  * @check_usb_thermal_prot_work:
@@ -252,6 +260,9 @@ struct ab8500_charger {
bool usb_device_is_unrecognised;
bool autopower;
int invalid_charger_detect_state;
+   bool is_usb_host;
+   int is_aca_rid;
+   atomic_t current_stepping_sessions;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
struct abx500_charger_platform_data *pdata;
@@ -264,17 +275,19 @@ struct ab8500_charger {
struct ab8500_charger_info usb;
struct regulator *regu;
struct workqueue_struct *

[PATCH 32/57] power: ab8500_charger: Do not touch VBUSOVV bits

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Do not touch the VBUSOVV in USBCHTRL2 when running on AB8505.

Signed-off-by: Jonas Aaberg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
---
 drivers/power/ab8500_charger.c|   22 --
 include/linux/mfd/abx500/ab8500.h |   10 ++
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 071c7c2..2a323cf 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2667,13 +2667,23 @@ static int ab8500_charger_init_hw_registers(struct 
ab8500_charger *di)
}
}
 
-   /* VBUS OVV set to 6.3V and enable automatic current limitiation */
-   ret = abx500_set_register_interruptible(di->dev,
-   AB8500_CHARGER,
-   AB8500_USBCH_CTRL2_REG,
-   VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
+   if (is_ab9540_2p0(di->parent) || is_ab8505_2p0(di->parent))
+   ret = abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_CHARGER,
+   AB8500_USBCH_CTRL2_REG,
+   VBUS_AUTO_IN_CURR_LIM_ENA,
+   VBUS_AUTO_IN_CURR_LIM_ENA);
+   else
+   /*
+* VBUS OVV set to 6.3V and enable automatic current limitation
+*/
+   ret = abx500_set_register_interruptible(di->dev,
+   AB8500_CHARGER,
+   AB8500_USBCH_CTRL2_REG,
+   VBUS_OVV_SELECT_6P3V | VBUS_AUTO_IN_CURR_LIM_ENA);
if (ret) {
-   dev_err(di->dev, "failed to set VBUS OVV\n");
+   dev_err(di->dev,
+   "failed to set automatic current limitation\n");
goto out;
}
 
diff --git a/include/linux/mfd/abx500/ab8500.h 
b/include/linux/mfd/abx500/ab8500.h
index 087b445..5a4b186 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -351,6 +351,16 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
 }
 
+static inline int is_ab8505_2p0(struct ab8500 *ab)
+{
+   return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+static inline int is_ab9540_2p0(struct ab8500 *ab)
+{
+   return (is_ab9540(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
 int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq);
 
 #endif /* MFD_AB8500_H */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 30/57] power: ab8500: Flush & sync all works

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Flush and sync all workqueues at suspend to avoid
that we suspend in the middle of a work.

Signed-off-by: Jonas Aaberg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Marcus COOPER 
---
 drivers/power/ab8500_charger.c |   11 +++
 drivers/power/ab8500_fg.c  |5 +
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index ee5ad7b..071c7c2 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2862,6 +2862,17 @@ static int ab8500_charger_suspend(struct platform_device 
*pdev,
if (delayed_work_pending(&di->check_hw_failure_work))
cancel_delayed_work(&di->check_hw_failure_work);
 
+   flush_delayed_work_sync(&di->attach_work);
+   flush_delayed_work_sync(&di->usb_charger_attached_work);
+   flush_delayed_work_sync(&di->ac_charger_attached_work);
+   flush_delayed_work_sync(&di->check_usbchgnotok_work);
+   flush_delayed_work_sync(&di->check_vbat_work);
+   flush_delayed_work_sync(&di->kick_wd_work);
+
+   flush_work_sync(&di->usb_link_status_work);
+   flush_work_sync(&di->ac_work);
+   flush_work_sync(&di->detect_usb_type_work);
+
return 0;
 }
 #else
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index e7a0e1f..0e71e7e 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2626,6 +2626,11 @@ static int ab8500_fg_suspend(struct platform_device 
*pdev,
struct ab8500_fg *di = platform_get_drvdata(pdev);
 
flush_delayed_work_sync(&di->fg_periodic_work);
+   flush_work_sync(&di->fg_work);
+   flush_work_sync(&di->fg_acc_cur_work);
+   flush_delayed_work_sync(&di->fg_reinit_work);
+   flush_delayed_work_sync(&di->fg_low_bat_work);
+   flush_delayed_work_sync(&di->fg_check_hw_failure_work);
 
/*
 * If the FG is enabled we will disable it before going to suspend
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 28/57] power: ab8500 - Accessing Autopower register fails

2012-09-25 Thread mathieu . poirier
From: Nicolas Guion 

The fallback software control register has moved in the ab8505
and ab9540.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Mattias WALLIN 
Reviewed-by: Nicolas GUION 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c |   53 +++-
 1 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 0a781a0..ee5ad7b 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -92,6 +92,8 @@
 
 #define CHG_WD_INTERVAL(60 * HZ)
 
+#define AB8500_SW_CONTROL_FALLBACK 0x03
+
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
USB_STAT_NOT_CONFIGURED,
@@ -307,42 +309,59 @@ static enum power_supply_property 
ab8500_charger_usb_props[] = {
 static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di,
bool fallback)
 {
+   u8 val;
u8 reg;
+   u8 bank;
+   u8 bit;
int ret;
 
dev_dbg(di->dev, "SW Fallback: %d\n", fallback);
 
+   if (is_ab8500(di->parent)) {
+   bank = 0x15;
+   reg = 0x0;
+   bit = 3;
+   } else {
+   bank = AB8500_SYS_CTRL1_BLOCK;
+   reg = AB8500_SW_CONTROL_FALLBACK;
+   bit = 0;
+   }
+
/* read the register containing fallback bit */
-   ret = abx500_get_register_interruptible(di->dev, 0x15, 0x00, ®);
-   if (ret) {
-   dev_err(di->dev, "%d write failed\n", __LINE__);
+   ret = abx500_get_register_interruptible(di->dev, bank, reg, &val);
+   if (ret < 0) {
+   dev_err(di->dev, "%d read failed\n", __LINE__);
return;
}
 
-   /* enable the OPT emulation registers */
-   ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x2);
-   if (ret) {
-   dev_err(di->dev, "%d write failed\n", __LINE__);
-   return;
+   if (is_ab8500(di->parent)) {
+   /* enable the OPT emulation registers */
+   ret = abx500_set_register_interruptible(di->dev,
+0x11, 0x00, 0x2);
+   if (ret) {
+   dev_err(di->dev, "%d write failed\n", __LINE__);
+   goto disable_otp;
+   }
}
 
if (fallback)
-   reg |= 0x8;
+   val |= (1 << bit);
else
-   reg &= ~0x8;
+   val &= ~(1 << bit);
 
/* write back the changed fallback bit value to register */
-   ret = abx500_set_register_interruptible(di->dev, 0x15, 0x00, reg);
+   ret = abx500_set_register_interruptible(di->dev, bank, reg, val);
if (ret) {
dev_err(di->dev, "%d write failed\n", __LINE__);
-   return;
}
 
-   /* disable the set OTP registers again */
-   ret = abx500_set_register_interruptible(di->dev, 0x11, 0x00, 0x0);
-   if (ret) {
-   dev_err(di->dev, "%d write failed\n", __LINE__);
-   return;
+disable_otp:
+   if (is_ab8500(di->parent)) {
+   /* disable the set OTP registers again */
+   ret = abx500_set_register_interruptible(di->dev,
+0x11, 0x00, 0x0);
+   if (ret)
+   dev_err(di->dev, "%d write failed\n", __LINE__);
}
 }
 
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 26/57] power: charge: update watchdog for pm2xxx support

2012-09-25 Thread mathieu . poirier
From: Loic Pallardy 

AB and PMxxx doesn't have same watchdog refresh period
Add watchdog to refresh period parameters in x500 charger structure,
this should kick watchdog every 30sec.
The AC charging should also kick both pm2xxx
and the AB charger watchdog.

Signed-off-by: Rajkumar Kasirajan 
Signed-off-by: Loic Pallardy 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Michel JAOUEN 
Reviewed-by: Marcus COOPER 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c|6 ++
 drivers/power/abx500_chargalg.c   |   23 +--
 include/linux/mfd/abx500/ux500_chargalg.h |3 +++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 3100f11..4129599 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -90,6 +90,8 @@
 
 #define CHARGER_STATUS_POLL 10 /* in ms */
 
+#define CHG_WD_INTERVAL(60 * HZ)
+
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
USB_STAT_NOT_CONFIGURED,
@@ -2945,7 +2947,9 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->ac_chg.max_out_curr = ab8500_charger_current_map[
ARRAY_SIZE(ab8500_charger_current_map) - 1];
+   di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
di->ac_chg.enabled = di->pdata->ac_enabled;
+   di->ac_chg.external = false;
 
/* USB supply */
/* power_supply base class */
@@ -2964,7 +2968,9 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->usb_chg.max_out_curr = ab8500_charger_current_map[
ARRAY_SIZE(ab8500_charger_current_map) - 1];
+   di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
di->usb_chg.enabled = di->pdata->usb_enabled;
+   di->usb_chg.external = false;
 
/* Create a work queue for the charger */
di->charger_wq =
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index ca87cb2..d3efc2a 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -453,8 +453,18 @@ static int abx500_chargalg_kick_watchdog(struct 
abx500_chargalg *di)
 {
/* Check if charger exists and kick watchdog if charging */
if (di->ac_chg && di->ac_chg->ops.kick_wd &&
-   di->chg_info.online_chg & AC_CHG)
+   di->chg_info.online_chg & AC_CHG) {
+   /*
+* If AB charger watchdog expired, pm2xxx charging
+* gets disabled. To be safe, kick both AB charger watchdog
+* and pm2xxx watchdog.
+*/
+   if (di->ac_chg->external &&
+   di->usb_chg && di->usb_chg->ops.kick_wd)
+   di->usb_chg->ops.kick_wd(di->usb_chg);
+
return di->ac_chg->ops.kick_wd(di->ac_chg);
+   }
else if (di->usb_chg && di->usb_chg->ops.kick_wd &&
di->chg_info.online_chg & USB_CHG)
return di->usb_chg->ops.kick_wd(di->usb_chg);
@@ -1591,6 +1601,8 @@ static void abx500_chargalg_periodic_work(struct 
work_struct *work)
 static void abx500_chargalg_wd_work(struct work_struct *work)
 {
int ret;
+   int refresh_time;
+
struct abx500_chargalg *di = container_of(work,
struct abx500_chargalg, chargalg_wd_work.work);
 
@@ -1600,8 +1612,15 @@ static void abx500_chargalg_wd_work(struct work_struct 
*work)
if (ret < 0)
dev_err(di->dev, "failed to kick watchdog\n");
 
+   if (di->chg_info.online_chg & AC_CHG)
+   refresh_time = di->ac_chg->wdt_refresh;
+   else if (di->chg_info.online_chg & USB_CHG)
+   refresh_time = di->usb_chg->wdt_refresh;
+   else
+   refresh_time = CHG_WD_INTERVAL;
+
queue_delayed_work(di->chargalg_wq,
-   &di->chargalg_wd_work, CHG_WD_INTERVAL);
+   &di->chargalg_wd_work, refresh_time);
 }
 
 /**
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h 
b/include/linux/mfd/abx500/ux500_chargalg.h
index 5b77a61..d43ac0f 100644
--- a/include/linux/mfd/abx500/ux500_chargalg.h
+++ b/include/linux/mfd/abx500/ux500_chargalg.h
@@ -28,13 +28,16 @@ struct ux500_charger_ops {
  * @max_out_volt   maximum output charger voltage in mV
  * @max_out_curr   maximum output charger current in mA
  * @enabledindicates if this charger is used or not
+ * @external   external charger unit (pm2xxx)
  */
 struct ux500_charger {
struct power_supply ps

[PATCH 08/57] power: ab8500_fg: flush sync on suspend

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Do flush sync on the fg workqueue at suspend instead of
just flushing it.

Signed-off-by: Jonas Aaberg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Johan BJORNSTEDT 
---
 drivers/power/ab8500_fg.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 342d118..1e02b00 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2437,7 +2437,7 @@ static int ab8500_fg_suspend(struct platform_device *pdev,
 {
struct ab8500_fg *di = platform_get_drvdata(pdev);
 
-   flush_delayed_work(&di->fg_periodic_work);
+   flush_delayed_work_sync(&di->fg_periodic_work);
 
/*
 * If the FG is enabled we will disable it before going to suspend
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 07/57] power: ab8500_bm: Detect removed charger

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Signed-off-by: Jonas Aaberg 
Signed-off-by: Mathieu Poirier 
---
 drivers/power/ab8500_charger.c |  122 +++-
 1 files changed, 121 insertions(+), 1 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index a7d0c3a..f7bba07 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -66,6 +66,11 @@
 #define MAIN_CH_NOK0x01
 #define VBUS_DET   0x80
 
+#define MAIN_CH_STATUS2_MAINCHGDROP0x80
+#define MAIN_CH_STATUS2_MAINCHARGERDETDBNC 0x40
+#define USB_CH_VBUSDROP0x40
+#define USB_CH_VBUSDETDBNC 0x01
+
 /* UsbLineStatus register bit masks */
 #define AB8500_USB_LINK_STATUS 0x78
 #define AB8500_STD_HOST_SUSP   0x18
@@ -80,6 +85,8 @@
 /* Step up/down delay in us */
 #define STEP_UDELAY1000
 
+#define CHARGER_STATUS_POLL 10 /* in ms */
+
 /* UsbLineStatus register - usb types */
 enum ab8500_charger_link_status {
USB_STAT_NOT_CONFIGURED,
@@ -201,6 +208,10 @@ struct ab8500_charger_usb_state {
  * @check_usbchgnotok_work:Work for checking USB charger not ok status
  * @kick_wd_work:  Work for kicking the charger watchdog in case
  * of ABB rev 1.* due to the watchog logic bug
+ * @ac_charger_attached_work:  Work for checking if AC charger is still
+ * connected
+ * @usb_charger_attached_work: Work for checking if USB charger is still
+ * connected
  * @ac_work:   Work for checking AC charger connection
  * @detect_usb_type_work:  Work for detecting the USB type connected
  * @usb_link_status_work:  Work for checking the new USB link status
@@ -237,6 +248,8 @@ struct ab8500_charger {
struct delayed_work check_hw_failure_work;
struct delayed_work check_usbchgnotok_work;
struct delayed_work kick_wd_work;
+   struct delayed_work ac_charger_attached_work;
+   struct delayed_work usb_charger_attached_work;
struct work_struct ac_work;
struct work_struct detect_usb_type_work;
struct work_struct usb_link_status_work;
@@ -347,6 +360,15 @@ static void ab8500_charger_set_usb_connected(struct 
ab8500_charger *di,
dev_dbg(di->dev, "USB connected:%i\n", connected);
di->usb.charger_connected = connected;
sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present");
+
+   if (connected) {
+   queue_delayed_work(di->charger_wq,
+  &di->usb_charger_attached_work,
+  HZ);
+   } else {
+   cancel_delayed_work_sync
+   (&di->usb_charger_attached_work);
+   }
}
 }
 
@@ -1703,6 +1725,81 @@ static void ab8500_charger_ac_work(struct work_struct 
*work)
sysfs_notify(&di->ac_chg.psy.dev->kobj, NULL, "present");
 }
 
+static void ab8500_charger_usb_attached_work(struct work_struct *work)
+{
+   int i;
+   int ret;
+   u8 statval;
+   struct ab8500_charger *di = container_of(work,
+struct ab8500_charger,
+usb_charger_attached_work.work);
+
+   for (i = 0 ; i < 10; i++) {
+   ret = abx500_get_register_interruptible(di->dev,
+   AB8500_CHARGER,
+   AB8500_CH_USBCH_STAT1_REG,
+   &statval);
+   if (ret < 0) {
+   dev_err(di->dev, "ab8500 read failed %d\n",
+   __LINE__);
+   goto reschedule;
+   }
+   if ((statval & (USB_CH_VBUSDROP |
+   USB_CH_VBUSDETDBNC)) !=
+   (USB_CH_VBUSDROP | USB_CH_VBUSDETDBNC))
+   goto reschedule;
+
+   msleep(CHARGER_STATUS_POLL);
+   }
+
+   (void) ab8500_charger_usb_en(&di->usb_chg, 0, 0, 0);
+
+   return;
+reschedule:
+   queue_delayed_work(di->charger_wq,
+  &di->usb_charger_attached_work,
+  HZ);
+}
+
+static void ab8500_charger_ac_attached_work(struct work_struct *work)
+{
+
+   int i;
+   int ret;
+   u8 statval;
+   struct ab8500_charger *di = container_of(work,
+struct ab8500_charger,
+ac_charger_attached_work.work);
+
+   for (i = 0 ; i < 10; i++) {
+   

[PATCH 14/57] power: Adds support for Car/Travel Adapters

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

The Travel and Carkit adapter should be handled directly by
the charger driver.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c   |   94 +-
 include/linux/mfd/abx500/ab8500-bm.h |1 +
 2 files changed, 70 insertions(+), 25 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 06a7c8b..09edd9c 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -105,6 +105,18 @@ enum ab8500_charger_link_status {
USB_STAT_HM_IDGND,
USB_STAT_RESERVED,
USB_STAT_NOT_VALID_LINK,
+   USB_STAT_PHY_EN,
+   USB_STAT_SUP_NO_IDGND_VBUS,
+   USB_STAT_SUP_IDGND_VBUS,
+   USB_STAT_CHARGER_LINE_1,
+   USB_STAT_CARKIT_1,
+   USB_STAT_CARKIT_2,
+   USB_STAT_ACA_DOCK_CHARGER,
+   USB_STAT_SAMSUNG_USB_PHY_DIS,
+   USB_STAT_SAMSUNG_USB_PHY_ENA,
+   USB_STAT_SAMSUNG_UART_PHY_DIS,
+   USB_STAT_SAMSUNG_UART_PHY_ENA,
+   USB_STAT_MOTOROLA_USB_PHY_ENA,
 };
 
 enum ab8500_usb_state {
@@ -577,7 +589,7 @@ static int ab8500_charger_detect_chargers(struct 
ab8500_charger *di)
  * Returns error code in case of failure else 0 on success
  */
 static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
-   enum ab8500_charger_link_status link_status)
+   enum ab8500_charger_link_status link_status)
 {
int ret = 0;
 
@@ -585,16 +597,20 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
case USB_STAT_STD_HOST_NC:
case USB_STAT_STD_HOST_C_NS:
case USB_STAT_STD_HOST_C_S:
-   dev_dbg(di->dev, "USB Type - Standard host is "
-   "detected through USB driver\n");
+   dev_dbg(di->dev, "USB Type - Standard host is ");
+   dev_dbg(di->dev, "detected through USB driver\n");
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09;
break;
case USB_STAT_HOST_CHG_HS_CHIRP:
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+   dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+   di->max_usb_in_curr);
break;
case USB_STAT_HOST_CHG_HS:
case USB_STAT_ACA_RID_C_HS:
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9;
+   dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+   di->max_usb_in_curr);
break;
case USB_STAT_ACA_RID_A:
/*
@@ -602,6 +618,8 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
 * can consume (300mA). Closest level is 1100mA
 */
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P1;
+   dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+   di->max_usb_in_curr);
break;
case USB_STAT_ACA_RID_B:
/*
@@ -609,34 +627,50 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
 * 100mA for potential accessory). Closest level is 1300mA
 */
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P3;
+   dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+   di->max_usb_in_curr);
break;
-   case USB_STAT_DEDICATED_CHG:
case USB_STAT_HOST_CHG_NM:
-   case USB_STAT_ACA_RID_C_HS_CHIRP:
+   case USB_STAT_DEDICATED_CHG:
case USB_STAT_ACA_RID_C_NM:
+   case USB_STAT_ACA_RID_C_HS_CHIRP:
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
-   break;
-   case USB_STAT_RESERVED:
-   /*
-* This state is used to indicate that VBUS has dropped below
-* the detection level 4 times in a row. This is due to the
-* charger output current is set to high making the charger
-* voltage collapse. This have to be propagated through to
-* chargalg. This is done using the property
-* POWER_SUPPLY_PROP_CURRENT_AVG = 1
-*/
-   di->flags.vbus_collapse = true;
-   dev_dbg(di->dev, "USB Type - USB_STAT_RESERVED "
-   "VBUS has collapsed\n");
-   ret = -1;
+   dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
+   di->max_usb_in_curr);
break;
case USB_STAT_HM_IDGND:
-   case USB_STAT_NOT_CONFIGURED:
case USB_STAT_NOT_VALID_LINK:
+   case USB_STAT_NOT_CONFIGURED:
dev_err(di->dev, "U

[PATCH 16/57] power: bm remove superfluous BTEMP thermal comp.

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

BTEMP thermal compensation factor times 10 is applied in two
places, probe and get_property. Removed from probe.

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_btemp.c |4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 04f9dec..74cddba 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -1026,8 +1026,8 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
ab8500_btemp_periodic_work);
 
/* Set BTEMP thermal limits. Low and Med are fixed */
-   di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT * 10;
-   di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT * 10;
+   di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
+   di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
 
ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
AB8500_BTEMP_HIGH_TH, &val);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 21/57] power: Overflow in current calculation

2012-09-25 Thread mathieu . poirier
From: Paer-Olof Haakansson 

When calculating the average current the nominator will
overflow when the charging current is high.

Signed-off-by: Henrik Sölver 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Par-Olof HAKANSSON 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |   15 ---
 1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 46010ec..7c42150 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -805,15 +805,13 @@ static void ab8500_fg_acc_cur_work(struct work_struct 
*work)
 
/*
 * Convert to unit value in mA
-* Full scale input voltage is
-* 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA
-* Given a 250ms conversion cycle time the LSB corresponds
-* to 112.9 nAh. Convert to current by dividing by the conversion
+* by dividing by the conversion
 * time in hours (= samples / (3600 * 4)h)
-* 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+* and multiply with 1000
 */
-   di->avg_curr = (val * QLSB_NANO_AMP_HOURS_X10 * 36) /
-   (1000 * di->bat->fg_res * (di->fg_samples / 4));
+
+   di->avg_curr = (di->accu_charge * 36) /
+   ((di->fg_samples / 4) * 10);
 
di->flags.conv_done = true;
 
@@ -821,6 +819,9 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work)
 
queue_work(di->fg_wq, &di->fg_work);
 
+   dev_dbg(di->dev,
+   "fg_res: %d, fg_samples: %d, gasg: %d, accu_charge: %d\n",
+   di->bat->fg_res, di->fg_samples, val, di->accu_charge);
return;
 exit:
dev_err(di->dev,
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 25/57] power: ab8500: adaptation to ab version

2012-09-25 Thread mathieu . poirier
From: Michel JAOUEN 

Add AB9540 and AB8505 support to ab8500_temp
driver.

Signed-off-by: Rajkumar Kasirajan 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Michel JAOUEN 
Reviewed-by: Marcus COOPER 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_btemp.c |   71 ++---
 include/linux/mfd/abx500/ab8500-bm.h |2 +
 2 files changed, 58 insertions(+), 15 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 74cddba..506f124 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -37,6 +37,9 @@
 #define BTEMP_BATCTRL_CURR_SRC_7UA 7
 #define BTEMP_BATCTRL_CURR_SRC_20UA20
 
+#define BTEMP_BATCTRL_CURR_SRC_16UA16
+#define BTEMP_BATCTRL_CURR_SRC_18UA18
+
 #define to_ab8500_btemp_device_info(x) container_of((x), \
struct ab8500_btemp, btemp_psy);
 
@@ -212,10 +215,18 @@ static int ab8500_btemp_curr_source_enable(struct 
ab8500_btemp *di,
 
/* Only do this for batteries with internal NTC */
if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
-   if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
-   curr = BAT_CTRL_7U_ENA;
-   else
-   curr = BAT_CTRL_20U_ENA;
+
+   if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_16UA)
+   curr = BAT_CTRL_16U_ENA;
+   else
+   curr = BAT_CTRL_18U_ENA;
+   } else {
+   if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
+   curr = BAT_CTRL_7U_ENA;
+   else
+   curr = BAT_CTRL_20U_ENA;
+   }
 
dev_dbg(di->dev, "Set BATCTRL %duA\n", di->curr_source);
 
@@ -246,11 +257,22 @@ static int ab8500_btemp_curr_source_enable(struct 
ab8500_btemp *di,
} else if (di->bat->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
dev_dbg(di->dev, "Disable BATCTRL curr source\n");
 
-   /* Write 0 to the curr bits */
-   ret = abx500_mask_and_set_register_interruptible(di->dev,
-   AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
-   BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
-   ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+   if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   /* Write 0 to the curr bits */
+   ret = abx500_mask_and_set_register_interruptible(
+   di->dev,
+   AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+   BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA,
+   ~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA));
+   } else {
+   /* Write 0 to the curr bits */
+   ret = abx500_mask_and_set_register_interruptible(
+   di->dev,
+   AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+   BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
+   ~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+   }
+
if (ret) {
dev_err(di->dev, "%s failed disabling current source\n",
__func__);
@@ -292,11 +314,20 @@ static int ab8500_btemp_curr_source_enable(struct 
ab8500_btemp *di,
 * if we got an error above
 */
 disable_curr_source:
-   /* Write 0 to the curr bits */
-   ret = abx500_mask_and_set_register_interruptible(di->dev,
+   if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+   /* Write 0 to the curr bits */
+   ret = abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+   BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA,
+   ~(BAT_CTRL_16U_ENA | BAT_CTRL_18U_ENA));
+   } else {
+   /* Write 0 to the curr bits */
+   ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA,
~(BAT_CTRL_7U_ENA | BAT_CTRL_20U_ENA));
+   }
+
if (ret) {
dev_err(di->dev, "%s failed disabling current source\n",
__func__);
@@ -510,8 +541,11 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
 {
int res;
u8 i;
+   if (is_ab9540(di->parent) || is_ab8505(di->parent))
+   di->curr_source = BTEMP_BATCTRL_CURR_SR

[PATCH 23/57] power: Add plaform data charger configurables

2012-09-25 Thread mathieu . poirier
From: Loic Pallardy 

Allow to indicate wheter AC and USB charge capabilities are
supported from platform data.

Signed-off-by: Loic Pallardy 
Signed-off-by: Mathieu Poirier 
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/58093
Reviewed-by: Marcus COOPER 
Reviewed-by: Olivier CLERGEAUD 
---
 drivers/power/ab8500_charger.c|   36 ++--
 include/linux/mfd/abx500.h|2 +
 include/linux/mfd/abx500/ux500_chargalg.h |2 +
 3 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index cbc9fd7..3100f11 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -2878,8 +2878,11 @@ static int __devexit ab8500_charger_remove(struct 
platform_device *pdev)
destroy_workqueue(di->charger_wq);
 
flush_scheduled_work();
-   power_supply_unregister(&di->usb_chg.psy);
-   power_supply_unregister(&di->ac_chg.psy);
+   if (di->usb_chg.enabled)
+   power_supply_unregister(&di->usb_chg.psy);
+   if (di->ac_chg.enabled)
+   power_supply_unregister(&di->ac_chg.psy);
+
platform_set_drvdata(pdev, NULL);
kfree(di);
 
@@ -2942,6 +2945,7 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->ac_chg.max_out_curr = ab8500_charger_current_map[
ARRAY_SIZE(ab8500_charger_current_map) - 1];
+   di->ac_chg.enabled = di->pdata->ac_enabled;
 
/* USB supply */
/* power_supply base class */
@@ -2960,7 +2964,7 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
di->usb_chg.max_out_curr = ab8500_charger_current_map[
ARRAY_SIZE(ab8500_charger_current_map) - 1];
-
+   di->usb_chg.enabled = di->pdata->usb_enabled;
 
/* Create a work queue for the charger */
di->charger_wq =
@@ -3036,17 +3040,21 @@ static int __devinit ab8500_charger_probe(struct 
platform_device *pdev)
}
 
/* Register AC charger class */
-   ret = power_supply_register(di->dev, &di->ac_chg.psy);
-   if (ret) {
-   dev_err(di->dev, "failed to register AC charger\n");
-   goto free_regulator;
+   if (di->ac_chg.enabled) {
+   ret = power_supply_register(di->dev, &di->ac_chg.psy);
+   if (ret) {
+   dev_err(di->dev, "failed to register AC charger\n");
+   goto free_regulator;
+   }
}
 
/* Register USB charger class */
-   ret = power_supply_register(di->dev, &di->usb_chg.psy);
-   if (ret) {
-   dev_err(di->dev, "failed to register USB charger\n");
-   goto free_ac;
+   if (di->usb_chg.enabled) {
+   ret = power_supply_register(di->dev, &di->usb_chg.psy);
+   if (ret) {
+   dev_err(di->dev, "failed to register USB charger\n");
+   goto free_ac;
+   }
}
 
di->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2);
@@ -3122,9 +3130,11 @@ free_irq:
 put_usb_phy:
usb_put_phy(di->usb_phy);
 free_usb:
-   power_supply_unregister(&di->usb_chg.psy);
+   if (di->usb_chg.enabled)
+   power_supply_unregister(&di->usb_chg.psy);
 free_ac:
-   power_supply_unregister(&di->ac_chg.psy);
+   if (di->ac_chg.enabled)
+   power_supply_unregister(&di->ac_chg.psy);
 free_regulator:
regulator_put(di->regu);
 free_charger_wq:
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 4d44a10..eef1ddc 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -398,6 +398,8 @@ struct abx500_charger_platform_data {
char **supplied_to;
size_t num_supplicants;
bool autopower_cfg;
+   bool ac_enabled;
+   bool usb_enabled;
 };
 
 struct abx500_btemp_platform_data {
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h 
b/include/linux/mfd/abx500/ux500_chargalg.h
index 9b07725..5b77a61 100644
--- a/include/linux/mfd/abx500/ux500_chargalg.h
+++ b/include/linux/mfd/abx500/ux500_chargalg.h
@@ -27,12 +27,14 @@ struct ux500_charger_ops {
  * @opsux500 charger operations
  * @max_out_volt   maximum output charger voltage in mV
  * @max_out_curr   maximum output charger current in mA
+ * @enabledindicates if this charger is used or not
  */
 struct ux500_charger {
struct power_supply psy;
struct ux500_charger_ops ops;
int max_out_volt;
int max_out_curr;
+   bool enabled;
 };
 
 #endif
-- 

[PATCH 22/57] power: AB workaround for invalid charger

2012-09-25 Thread mathieu . poirier
From: Henrik Sölver 

AB8500 refuses to start charging when some types of non standard
chargers are connected. This change force the AB to start charging.

Signed-off-by: Henrik Sölver 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Yvan FILLION 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c |   70 +--
 1 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 7cd4165..cbc9fd7 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -203,6 +203,7 @@ struct ab8500_charger_usb_state {
  * @old_vbat   Previously measured battery voltage
  * @usb_device_is_unrecognised USB device is unrecognised by the hardware
  * @autopower  Indicate if we should have automatic pwron after pwrloss
+ * @invalid_charger_detect_state   State when forcing AB to use invalid 
charger
  * @parent:Pointer to the struct ab8500
  * @gpadc: Pointer to the struct gpadc
  * @pdata: Pointer to the abx500_charger platform data
@@ -246,6 +247,7 @@ struct ab8500_charger {
int old_vbat;
bool usb_device_is_unrecognised;
bool autopower;
+   int invalid_charger_detect_state;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
struct abx500_charger_platform_data *pdata;
@@ -650,7 +652,6 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
break;
}
case USB_STAT_HM_IDGND:
-   case USB_STAT_NOT_VALID_LINK:
dev_err(di->dev, "USB Type - Charging not allowed\n");
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
ret = -ENXIO;
@@ -679,6 +680,9 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
di->max_usb_in_curr);
+   case USB_STAT_NOT_VALID_LINK:
+   dev_err(di->dev, "USB Type invalid - try charging anyway\n");
+   di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
break;
 
default:
@@ -1945,7 +1949,9 @@ static void ab8500_charger_usb_link_attach_work(struct 
work_struct *work)
  */
 static void ab8500_charger_usb_link_status_work(struct work_struct *work)
 {
+   int detected_chargers;
int ret;
+   u8 val;
 
struct ab8500_charger *di = container_of(work,
struct ab8500_charger, usb_link_status_work);
@@ -1955,11 +1961,66 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
 * synchronously, we have the check if  is
 * connected by reading the status register
 */
-   ret = ab8500_charger_detect_chargers(di);
-   if (ret < 0)
+   detected_chargers = ab8500_charger_detect_chargers(di);
+   if (detected_chargers < 0)
return;
 
-   if (!(ret & USB_PW_CONN)) {
+   /*
+* Some chargers that breaks the USB spec is
+* identified as invalid by AB8500 and it refuse
+* to start the charging process. but by jumping
+* thru a few hoops it can be forced to start.
+*/
+   ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+   AB8500_USB_LINE_STAT_REG, &val);
+   if (ret >= 0)
+   dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val);
+   else
+   dev_dbg(di->dev, "Error reading USB link status\n");
+
+   if (detected_chargers & USB_PW_CONN) {
+   if (((val & AB8500_USB_LINK_STATUS) >> 3) ==
+   USB_STAT_NOT_VALID_LINK &&
+   di->invalid_charger_detect_state == 0) {
+   dev_dbg(di->dev,
+"Invalid charger detected, state= 0\n");
+   /*Enable charger*/
+   abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_CHARGER,
+   AB8500_USBCH_CTRL1_REG,
+   0x01, 0x01)
+   /*Enable charger detection*/
+   abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_USB,
+   AB8500_MCH_IPT_CURLVL_REG,
+   0x01, 0x01);
+   di->invalid_charger_detect_state = 1;
+   /*exit and wait for new link status interrupt.*/
+   return;
+
+   }
+  

[PATCH 20/57] power: Adds support for legacy USB chargers

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

A Legacy USB charger should be handled directly by the charger
driver.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_charger.c |   66 ++-
 1 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 4155feb..7cd4165 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -85,6 +85,9 @@
 /* Step up/down delay in us */
 #define STEP_UDELAY1000
 
+/* Wait for enumeration before charging in ms */
+#define WAIT_FOR_USB_ENUMERATION   (5 * 1000)
+
 #define CHARGER_STATUS_POLL 10 /* in ms */
 
 /* UsbLineStatus register - usb types */
@@ -198,6 +201,7 @@ struct ab8500_charger_usb_state {
  * charger is enabled
  * @vbat   Battery voltage
  * @old_vbat   Previously measured battery voltage
+ * @usb_device_is_unrecognised USB device is unrecognised by the hardware
  * @autopower  Indicate if we should have automatic pwron after pwrloss
  * @parent:Pointer to the struct ab8500
  * @gpadc: Pointer to the struct gpadc
@@ -216,6 +220,7 @@ struct ab8500_charger_usb_state {
  * @check_usbchgnotok_work:Work for checking USB charger not ok status
  * @kick_wd_work:  Work for kicking the charger watchdog in case
  * of ABB rev 1.* due to the watchog logic bug
+ * @attach_work:   Work for checking the usb enumeration
  * @ac_charger_attached_work:  Work for checking if AC charger is still
  * connected
  * @usb_charger_attached_work: Work for checking if USB charger is still
@@ -239,6 +244,7 @@ struct ab8500_charger {
bool vddadc_en_usb;
int vbat;
int old_vbat;
+   bool usb_device_is_unrecognised;
bool autopower;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
@@ -256,6 +262,7 @@ struct ab8500_charger {
struct delayed_work check_hw_failure_work;
struct delayed_work check_usbchgnotok_work;
struct delayed_work kick_wd_work;
+   struct delayed_work attach_work;
struct delayed_work ac_charger_attached_work;
struct delayed_work usb_charger_attached_work;
struct work_struct ac_work;
@@ -588,6 +595,8 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
 {
int ret = 0;
 
+   di->usb_device_is_unrecognised = false;
+
switch (link_status) {
case USB_STAT_STD_HOST_NC:
case USB_STAT_STD_HOST_C_NS:
@@ -633,9 +642,15 @@ static int ab8500_charger_max_usb_curr(struct 
ab8500_charger *di,
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
di->max_usb_in_curr);
break;
+   case USB_STAT_NOT_CONFIGURED:
+   if (di->vbus_detected) {
+   di->usb_device_is_unrecognised = true;
+   dev_dbg(di->dev, "USB Type - Legacy charger.\n");
+   di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+   break;
+   }
case USB_STAT_HM_IDGND:
case USB_STAT_NOT_VALID_LINK:
-   case USB_STAT_NOT_CONFIGURED:
dev_err(di->dev, "USB Type - Charging not allowed\n");
di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
ret = -ENXIO;
@@ -1899,6 +1914,30 @@ static void ab8500_charger_detect_usb_type_work(struct 
work_struct *work)
 }
 
 /**
+ * ab8500_charger_usb_link_attach_work() - delayd work to detect USB type
+ * @work:  pointer to the work_struct structure
+ *
+ * Detect the type of USB plugged
+ */
+static void ab8500_charger_usb_link_attach_work(struct work_struct *work)
+{
+   int ret;
+
+   struct ab8500_charger *di = container_of(work,
+   struct ab8500_charger, attach_work.work);
+
+   /* Update maximum input current if USB enumeration is not detected */
+   if (!di->usb.charger_online) {
+   ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+   if (ret)
+   return;
+   }
+
+   ab8500_charger_set_usb_connected(di, true);
+   ab8500_power_supply_changed(di, &di->usb_chg.psy);
+}
+
+/**
  * ab8500_charger_usb_link_status_work() - work to detect USB type
  * @work:  pointer to the work_struct structure
  *
@@ -1928,14 +1967,20 @@ static void ab8500_charger_usb_link_status_work(struct 
work_struct *work)
di->vbus_detected = 1;
ret = ab8500_charger_read_usb_type(di);
if (!ret) {
-   /* Update maximum input current */
-   ret = ab8500_charger_set_vbus_in_curr(di,
-   

[PATCH 19/57] power: remove unused defines.

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

Cleanup of the ab8500_charger driver.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_charger.c |5 -
 1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 09edd9c..4155feb 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -112,11 +112,6 @@ enum ab8500_charger_link_status {
USB_STAT_CARKIT_1,
USB_STAT_CARKIT_2,
USB_STAT_ACA_DOCK_CHARGER,
-   USB_STAT_SAMSUNG_USB_PHY_DIS,
-   USB_STAT_SAMSUNG_USB_PHY_ENA,
-   USB_STAT_SAMSUNG_UART_PHY_DIS,
-   USB_STAT_SAMSUNG_UART_PHY_ENA,
-   USB_STAT_MOTOROLA_USB_PHY_ENA,
 };
 
 enum ab8500_usb_state {
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 17/57] power: ab8500_bm: Added support for BATT_OVV

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

Add support for the battery over-voltage situation

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_fg.c |   32 
 1 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index c4d9307..8507254 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -1842,24 +1842,26 @@ static void ab8500_fg_check_hw_failure_work(struct 
work_struct *work)
 * If we have had a battery over-voltage situation,
 * check ovv-bit to see if it should be reset.
 */
-   if (di->flags.bat_ovv) {
-   ret = abx500_get_register_interruptible(di->dev,
-   AB8500_CHARGER, AB8500_CH_STAT_REG,
-   ®_value);
-   if (ret < 0) {
-   dev_err(di->dev, "%s ab8500 read failed\n", __func__);
-   return;
-   }
-   if ((reg_value & BATT_OVV) != BATT_OVV) {
-   dev_dbg(di->dev, "Battery recovered from OVV\n");
-   di->flags.bat_ovv = false;
+   ret = abx500_get_register_interruptible(di->dev,
+   AB8500_CHARGER, AB8500_CH_STAT_REG,
+   ®_value);
+   if (ret < 0) {
+   dev_err(di->dev, "%s ab8500 read failed\n", __func__);
+   return;
+   }
+   if ((reg_value & BATT_OVV) == BATT_OVV) {
+   if (!di->flags.bat_ovv) {
+   dev_dbg(di->dev, "Battery OVV\n");
+   di->flags.bat_ovv = true;
power_supply_changed(&di->fg_psy);
-   return;
}
-
/* Not yet recovered from ovv, reschedule this test */
queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work,
-  round_jiffies(HZ));
+   HZ);
+   } else {
+   dev_dbg(di->dev, "Battery recovered from OVV\n");
+   di->flags.bat_ovv = false;
+   power_supply_changed(&di->fg_psy);
}
 }
 
@@ -2039,8 +2041,6 @@ static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, 
void *_di)
struct ab8500_fg *di = _di;
 
dev_dbg(di->dev, "Battery OVV\n");
-   di->flags.bat_ovv = true;
-   power_supply_changed(&di->fg_psy);
 
/* Schedule a new HW failure check */
queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, 0);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 15/57] power: ab8500_fg: Round capacity output

2012-09-25 Thread mathieu . poirier
From: pender01 

Round the capacity values for better enduser experience.

Signed-off-by: pender01 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |   28 +++-
 1 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 492f6bf..c4d9307 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -31,6 +31,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define MILLI_TO_MICRO 1000
 #define FG_LSB_IN_MA   1627
@@ -1160,7 +1161,7 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di)
 {
int ret, percent;
 
-   percent = di->bat_cap.permille / 10;
+   percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
 
if (percent <= di->bat->cap_levels->critical ||
di->flags.low_bat)
@@ -1281,6 +1282,7 @@ static void ab8500_fg_update_cap_scalers(struct ab8500_fg 
*di)
 static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
 {
bool changed = false;
+   int percent = DIV_ROUND_CLOSEST(di->bat_cap.permille, 10);
 
di->bat_cap.level = ab8500_fg_capacity_level(di);
 
@@ -1312,6 +1314,7 @@ static void ab8500_fg_check_capacity_limits(struct 
ab8500_fg *di, bool init)
dev_dbg(di->dev, "Battery low, set capacity to 0\n");
di->bat_cap.prev_percent = 0;
di->bat_cap.permille = 0;
+   percent = 0;
di->bat_cap.prev_mah = 0;
di->bat_cap.mah = 0;
changed = true;
@@ -1321,7 +1324,7 @@ static void ab8500_fg_check_capacity_limits(struct 
ab8500_fg *di, bool init)
 * and show 100% during maintenance charging (scaling).
 */
if (di->flags.force_full) {
-   di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+   di->bat_cap.prev_percent = percent;
di->bat_cap.prev_mah = di->bat_cap.mah;
 
changed = true;
@@ -1334,19 +1337,18 @@ static void ab8500_fg_check_capacity_limits(struct 
ab8500_fg *di, bool init)
di->bat_cap.prev_percent;
di->bat_cap.cap_scale.disable_cap_level = 100;
}
-   } else if (di->bat_cap.prev_percent !=
-   (di->bat_cap.permille) / 10) {
+   } else if (di->bat_cap.prev_percent != percent) {
dev_dbg(di->dev,
"battery reported full "
"but capacity dropping: %d\n",
-   di->bat_cap.permille / 10);
-   di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+   percent);
+   di->bat_cap.prev_percent = percent;
di->bat_cap.prev_mah = di->bat_cap.mah;
 
changed = true;
}
-   } else if (di->bat_cap.prev_percent != di->bat_cap.permille / 10) {
-   if (di->bat_cap.permille / 10 == 0) {
+   } else if (di->bat_cap.prev_percent != percent) {
+   if (percent == 0) {
/*
 * We will not report 0% unless we've got
 * the LOW_BAT IRQ, no matter what the FG
@@ -1356,11 +1358,11 @@ static void ab8500_fg_check_capacity_limits(struct 
ab8500_fg *di, bool init)
di->bat_cap.permille = 1;
di->bat_cap.prev_mah = 1;
di->bat_cap.mah = 1;
+   percent = 1;
 
changed = true;
} else if (!(!di->flags.charging &&
-   (di->bat_cap.permille / 10) >
-   di->bat_cap.prev_percent) || init) {
+   percent > di->bat_cap.prev_percent) || init) {
/*
 * We do not allow reported capacity to go up
 * unless we're charging or if we're in init
@@ -1368,9 +1370,9 @@ static void ab8500_fg_check_capacity_limits(struct 
ab8500_fg *di, bool init)
dev_dbg(di->dev,
"capacity changed from %d to %d (%d)\n",
di->bat_cap.prev_percent,
-   di->bat_cap.permille / 10,
+   percent,
di->bat_cap.permille);
-   di->bat_cap.prev_percent = di->bat_cap.permille / 10;
+   di->bat_cap.prev_perc

[PATCH 13/57] power: ab8500_bm: Ignore false btemp low interrupt

2012-09-25 Thread mathieu . poirier
From: Hakan Berg 

Ignore the low btemp interrupts for ab8500 3.0 and 3.3

Signed-off-by: Hakan Berg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_btemp.c  |   22 +++---
 include/linux/mfd/abx500/ab8500.h |5 +
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 45b10ad..04f9dec 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -622,9 +622,9 @@ static irqreturn_t ab8500_btemp_templow_handler(int irq, 
void *_di)
 {
struct ab8500_btemp *di = _di;
 
-   if (is_ab8500_2p0_or_earlier(di->parent)) {
-   dev_dbg(di->dev, "Ignore false btemp low irq"
-   " for ABB cut 1.0, 1.1 and 2.0\n");
+   if (is_ab8500_3p3_or_earlier(di->parent)) {
+   dev_dbg(di->dev, "Ignore false btemp low irq");
+   dev_dbg(di->dev, " for ABB cut 1.0, 1.1, 2.0 and 3.3\n");
} else {
dev_crit(di->dev, "Battery temperature lower than -10deg c\n");
 
@@ -738,30 +738,30 @@ static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
int temp = 0;
 
/*
-* The BTEMP events are not reliabe on AB8500 cut2.0
+* The BTEMP events are not reliabe on AB8500 cut3.3
 * and prior versions
 */
-   if (is_ab8500_2p0_or_earlier(di->parent)) {
+   if (is_ab8500_3p3_or_earlier(di->parent)) {
temp = di->bat_temp * 10;
} else {
if (di->events.btemp_low) {
if (temp > di->btemp_ranges.btemp_low_limit)
-   temp = di->btemp_ranges.btemp_low_limit;
+   temp = di->btemp_ranges.btemp_low_limit * 10;
else
temp = di->bat_temp * 10;
} else if (di->events.btemp_high) {
if (temp < di->btemp_ranges.btemp_high_limit)
-   temp = di->btemp_ranges.btemp_high_limit;
+   temp = di->btemp_ranges.btemp_high_limit * 10;
else
temp = di->bat_temp * 10;
} else if (di->events.btemp_lowmed) {
if (temp > di->btemp_ranges.btemp_med_limit)
-   temp = di->btemp_ranges.btemp_med_limit;
+   temp = di->btemp_ranges.btemp_med_limit * 10;
else
temp = di->bat_temp * 10;
} else if (di->events.btemp_medhigh) {
if (temp < di->btemp_ranges.btemp_med_limit)
-   temp = di->btemp_ranges.btemp_med_limit;
+   temp = di->btemp_ranges.btemp_med_limit * 10;
else
temp = di->bat_temp * 10;
} else
@@ -1026,8 +1026,8 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
ab8500_btemp_periodic_work);
 
/* Set BTEMP thermal limits. Low and Med are fixed */
-   di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
-   di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
+   di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT * 10;
+   di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT * 10;
 
ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
AB8500_BTEMP_HIGH_TH, &val);
diff --git a/include/linux/mfd/abx500/ab8500.h 
b/include/linux/mfd/abx500/ab8500.h
index db8a1e3..087b445 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -340,6 +340,11 @@ static inline int is_ab8500_2p0_or_earlier(struct ab8500 
*ab)
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
 }
 
+static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
+{
+   return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
+}
+
 /* exclude also ab8505, ab9540... */
 static inline int is_ab8500_2p0(struct ab8500 *ab)
 {
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 12/57] power: ab8500_fg: balance IRQ enable

2012-09-25 Thread mathieu . poirier
From: Rickard Andersson 

In case of time out error IRQ needs to be disabled
otherwise we will get unbalanced enable/disable pairs.

Signed-off-by: Rickard Andersson 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 7af616c..492f6bf 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -746,6 +746,7 @@ int ab8500_fg_inst_curr_blocking(struct ab8500_fg *di)
dev_dbg(di->dev, "%s instant current: %d", __func__, res);
return res;
 fail:
+   disable_irq(di->irq);
mutex_unlock(&di->cc_lock);
return ret;
 }
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 11/57] power: Recharge condition not optimal for battery

2012-09-25 Thread mathieu . poirier
From: Marcus Cooper 

Today the battery recharge is determined with a voltage threshold. This
voltage threshold is only valid when the battery is relaxed. In charging
algorithm the voltage read is the loaded battery voltage and no
compensation is done to get the relaxed voltage. When maintenance
charging is not selected, this makes the recharging condition to almost
immediately activate when there is a discharge present on the battery.

Depending on which vendor the battery comes from this behavior can wear
out the battery much faster than normal.

The fuelgauge driver is responsible to monitor the actual battery
capacity and is able to estimate the remaining capacity. It is better to
use the remaining capacity as a limit to determine when battery should
be recharged.

Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Hakan BERG 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c   |  157 +++
 drivers/power/abx500_chargalg.c |   59 +++
 include/linux/mfd/abx500.h  |6 +-
 3 files changed, 191 insertions(+), 31 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 0db17c7..7af616c 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -112,6 +112,13 @@ struct ab8500_fg_avg_cap {
int sum;
 };
 
+struct ab8500_fg_cap_scaling {
+   bool enable;
+   int cap_to_scale[2];
+   int disable_cap_level;
+   int scaled_cap;
+};
+
 struct ab8500_fg_battery_capacity {
int max_mah_design;
int max_mah;
@@ -122,6 +129,7 @@ struct ab8500_fg_battery_capacity {
int prev_percent;
int prev_level;
int user_mah;
+   struct ab8500_fg_cap_scaling cap_scale;
 };
 
 struct ab8500_fg_flags {
@@ -928,10 +936,11 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg 
*di)
resist = tbl[tbl_size - 1].resist;
}
 
-   dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d"
-   " fg resistance %d, total: %d (mOhm)\n",
-   __func__, di->bat_temp, resist, di->bat->fg_res / 10,
-   (di->bat->fg_res / 10) + resist);
+   dev_dbg(di->dev, "%s Temp: %d battery internal resistance: %d",
+   __func__, di->bat_temp, resist);
+   dev_dbg(di->dev, " fg resistance %d, total: %d (mOhm)\n",
+   di->bat->fg_res / 10,
+   (di->bat->fg_res / 10) + resist);
 
/* fg_res variable is in 0.1mOhm */
resist += di->bat->fg_res / 10;
@@ -1168,6 +1177,99 @@ static int ab8500_fg_capacity_level(struct ab8500_fg *di)
 }
 
 /**
+ * ab8500_fg_calculate_scaled_capacity() - Capacity scaling
+ * @di:pointer to the ab8500_fg structure
+ *
+ * Calculates the capacity to be shown to upper layers. Scales the capacity
+ * to have 100% as a reference from the actual capacity upon removal of charger
+ * when charging is in maintenance mode.
+ */
+static int ab8500_fg_calculate_scaled_capacity(struct ab8500_fg *di)
+{
+   struct ab8500_fg_cap_scaling *cs = &di->bat_cap.cap_scale;
+   int capacity = di->bat_cap.prev_percent;
+
+   if (!cs->enable)
+   return capacity;
+
+   /*
+* As long as we are in fully charge mode scale the capacity
+* to show 100%.
+*/
+   if (di->flags.fully_charged) {
+   cs->cap_to_scale[0] = 100;
+   cs->cap_to_scale[1] =
+   max(capacity, di->bat->fg_params->maint_thres);
+   dev_dbg(di->dev, "Scale cap with %d/%d\n",
+cs->cap_to_scale[0], cs->cap_to_scale[1]);
+   }
+
+   /* Calculates the scaled capacity. */
+   if ((cs->cap_to_scale[0] != cs->cap_to_scale[1])
+   && (cs->cap_to_scale[1] > 0))
+   capacity = min(100,
+DIV_ROUND_CLOSEST(di->bat_cap.prev_percent *
+cs->cap_to_scale[0],
+cs->cap_to_scale[1]));
+
+   if (di->flags.charging) {
+   if (capacity < cs->disable_cap_level) {
+   cs->disable_cap_level = capacity;
+   dev_dbg(di->dev, "Cap to stop scale lowered %d%%\n",
+   cs->disable_cap_level);
+   } else if (!di->flags.fully_charged) {
+   if (di->bat_cap.prev_percent >=
+   cs->disable_cap_level) {
+   dev_dbg(di->dev, "Disabling scaled capacity\n");
+   cs->enable = false;
+ 

[PATCH 10/57] power: ab8500_charger: Handle gpadc errors

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Gracefully handle gpadc conversion errors.

Signed-off-by: Jonas Aaberg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Johan BJORNSTEDT 
---
 drivers/power/ab8500_charger.c |   22 ++
 1 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index f7bba07..06a7c8b 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -157,6 +157,7 @@ struct ab8500_charger_info {
int charger_voltage;
int cv_active;
bool wd_expired;
+   int charger_current;
 };
 
 struct ab8500_charger_event_flags {
@@ -2341,6 +2342,7 @@ static int ab8500_charger_ac_get_property(struct 
power_supply *psy,
union power_supply_propval *val)
 {
struct ab8500_charger *di;
+   int ret;
 
di = to_ab8500_charger_ac_device_info(psy_to_ux500_charger(psy));
 
@@ -2362,7 +2364,10 @@ static int ab8500_charger_ac_get_property(struct 
power_supply *psy,
val->intval = di->ac.charger_connected;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-   di->ac.charger_voltage = ab8500_charger_get_ac_voltage(di);
+   ret = ab8500_charger_get_ac_voltage(di);
+   if (ret >= 0)
+   di->ac.charger_voltage = ret;
+   /* On error, use previous value */
val->intval = di->ac.charger_voltage * 1000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
@@ -2374,7 +2379,10 @@ static int ab8500_charger_ac_get_property(struct 
power_supply *psy,
val->intval = di->ac.cv_active;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
-   val->intval = ab8500_charger_get_ac_current(di) * 1000;
+   ret = ab8500_charger_get_ac_current(di);
+   if (ret >= 0)
+   di->ac.charger_current = ret;
+   val->intval = di->ac.charger_current * 1000;
break;
default:
return -EINVAL;
@@ -2401,6 +2409,7 @@ static int ab8500_charger_usb_get_property(struct 
power_supply *psy,
union power_supply_propval *val)
 {
struct ab8500_charger *di;
+   int ret;
 
di = to_ab8500_charger_usb_device_info(psy_to_ux500_charger(psy));
 
@@ -2424,7 +2433,9 @@ static int ab8500_charger_usb_get_property(struct 
power_supply *psy,
val->intval = di->usb.charger_connected;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-   di->usb.charger_voltage = ab8500_charger_get_vbus_voltage(di);
+   ret = ab8500_charger_get_vbus_voltage(di);
+   if (ret >= 0)
+   di->usb.charger_voltage = ret;
val->intval = di->usb.charger_voltage * 1000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
@@ -2436,7 +2447,10 @@ static int ab8500_charger_usb_get_property(struct 
power_supply *psy,
val->intval = di->usb.cv_active;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
-   val->intval = ab8500_charger_get_usb_current(di) * 1000;
+   ret = ab8500_charger_get_usb_current(di);
+   if (ret >= 0)
+   di->usb.charger_current = ret;
+   val->intval = di->usb.charger_current * 1000;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
/*
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 06/57] power: ab8500_bm: Skip first CCEOC irq for instant current

2012-09-25 Thread mathieu . poirier
From: Johan Bjornstedt 

When enabling the CCEOC irq we might get false interrupt
from ab8500-driver due to the latched value will be saved
and interpreted as an IRQ when enabled

Signed-off-by: Johan Bjornstedt 
Signed-off-by: Henrik Solver 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_btemp.c |   11 ++
 drivers/power/ab8500_fg.c|   63 +
 include/linux/mfd/abx500/ab8500-bm.h |6 +++
 3 files changed, 65 insertions(+), 15 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 41a8ce4..45b10ad 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -374,13 +374,10 @@ static int ab8500_btemp_get_batctrl_res(struct 
ab8500_btemp *di)
return ret;
}
 
-   /*
-* Since there is no interrupt when current measurement is done,
-* loop for over 250ms (250ms is one sample conversion time
-* with 32.768 Khz RTC clock). Note that a stop time must be set
-* since the ab8500_btemp_read_batctrl_voltage call can block and
-* take an unknown amount of time to complete.
-*/
+   do {
+   msleep(20);
+   } while (!ab8500_fg_inst_curr_started(di->fg));
+
i = 0;
 
do {
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index c098ddd..342d118 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -159,6 +159,7 @@ struct inst_curr_result_list {
  * @recovery_cnt:  Counter for recovery mode
  * @high_curr_cnt: Counter for high current mode
  * @init_cnt:  Counter for init mode
+ * @nbr_cceoc_irq_cnt  Counter for number of CCEOC irqs received since enabled
  * @recovery_needed:   Indicate if recovery is needed
  * @high_curr_mode:Indicate if we're in high current mode
  * @init_capacity: Indicate if initial capacity measuring should be done
@@ -166,6 +167,7 @@ struct inst_curr_result_list {
  * @calib_stateState during offset calibration
  * @discharge_state:   Current discharge state
  * @charge_state:  Current charge state
+ * @ab8500_fg_started  Completion struct used for the instant current start
  * @ab8500_fg_complete Completion struct used for the instant current reading
  * @flags: Structure for information about events triggered
  * @bat_cap:   Structure for battery capacity specific parameters
@@ -199,6 +201,7 @@ struct ab8500_fg {
int recovery_cnt;
int high_curr_cnt;
int init_cnt;
+   int nbr_cceoc_irq_cnt;
bool recovery_needed;
bool high_curr_mode;
bool init_capacity;
@@ -206,6 +209,7 @@ struct ab8500_fg {
enum ab8500_fg_calibration_state calib_state;
enum ab8500_fg_discharge_state discharge_state;
enum ab8500_fg_charge_state charge_state;
+   struct completion ab8500_fg_started;
struct completion ab8500_fg_complete;
struct ab8500_fg_flags flags;
struct ab8500_fg_battery_capacity bat_cap;
@@ -525,13 +529,14 @@ cc_err:
  * Note: This is part "one" and has to be called before
  * ab8500_fg_inst_curr_finalize()
  */
- int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
+int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
 {
u8 reg_val;
int ret;
 
mutex_lock(&di->cc_lock);
 
+   di->nbr_cceoc_irq_cnt = 0;
ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
AB8500_RTC_CC_CONF_REG, ®_val);
if (ret < 0)
@@ -559,6 +564,7 @@ cc_err:
}
 
/* Return and WFI */
+   INIT_COMPLETION(di->ab8500_fg_started);
INIT_COMPLETION(di->ab8500_fg_complete);
enable_irq(di->irq);
 
@@ -570,6 +576,17 @@ fail:
 }
 
 /**
+ * ab8500_fg_inst_curr_started() - check if fg conversion has started
+ * @di: pointer to the ab8500_fg structure
+ *
+ * Returns 1 if conversion started, 0 if still waiting
+ */
+int ab8500_fg_inst_curr_started(struct ab8500_fg *di)
+{
+   return completion_done(&di->ab8500_fg_started);
+}
+
+/**
  * ab8500_fg_inst_curr_done() - check if fg conversion is done
  * @di: pointer to the ab8500_fg structure
  *
@@ -597,13 +614,15 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, 
int *res)
int timeout;
 
if (!completion_done(&di->ab8500_fg_complete)) {
-   timeout = wait_for_completion_timeout(&di->ab8500_fg_complete,
+   timeout = wait_for_completion_timeout(
+   &di->ab8500_fg_complete,
INS_CURR_TIMEOUT);
dev_dbg(di->dev, "Finalize time: %d ms\n",
((INS_CURR_TIMEOUT - timeout) * 1000) / HZ);
if (!timeout) {
ret = -ETIME;
disable_irq(di->irq);
+ 

[PATCH 00/57] power: Upgrade to ux500 battery management driver

2012-09-25 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

This patch set upgrades the current ux500 battery management driver
to the latest HW and functionality.

Pull request for convenience:

The following changes since commit 56d27adcb536b7430d5f8a6240df8ad261eb00bd:

  Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile 
(2012-09-24 16:17:17 -0700)

are available in the git repository at:

  git://git.linaro.org/people/mpoirier/linux.git ux500-battery-management

Daniel WILLERUD (1):
  power: Add sysfs interfaces for capacity

Hakan Berg (10):
  power: ab8500_bm: Ignore false btemp low interrupt
  power: Adds support for Car/Travel Adapters
  power: bm remove superfluous BTEMP thermal comp.
  power: ab8500_bm: Added support for BATT_OVV
  power: ab8500_fg: Adjust for RF bursts voltage drops.
  power: ab8500_btemp: Filter btemp readings
  power: charging: Allow capacity to raise from 1%
  power: charging: Add AB8505_USB_LINK_STATUS
  power: ab8500-chargalg: update battery health on safety timer exp
  power: abx500_chargalg: Use hrtimer

Henrik Sölver (1):
  power: AB workaround for invalid charger

Johan Bjornstedt (2):
  power: ab8500_bm: Charger current step-up/down
  power: ab8500_bm: Skip first CCEOC irq for instant current

Jonas Aaberg (7):
  power: ab8500_btemp: Detect battery type in workqueue
  power: ab8500_bm: Detect removed charger
  power: ab8500_fg: flush sync on suspend
  power: ab8500_fg: usleep_range instead of short msleep
  power: ab8500_charger: Handle gpadc errors
  power: ab8500: Flush & sync all works
  power: ab8500_charger: Do not touch VBUSOVV bits

Kalle Komierowski (2):
  power: ab8500_bm: Don't clear the CCMuxOffset bit
  power: ab8500_bm: Quick re-attach charging behaviour

Loic Pallardy (3):
  power: Add plaform data charger configurables
  power: charge: update watchdog for pm2xxx support
  power: chargealg: Realign with upstream version

Marcus Cooper (8):
  power: Recharge condition not optimal for battery
  power: remove unused defines.
  power: Adds support for legacy USB chargers
  power: ab8500: ADC for battery thermistor
  power: ab8500: remove unecesary define flag
  power: ab8500_charger: Use USBLink1Status Register
  power: ab8500_charger: Add UsbLineCtrl2 reference
  power: abx500_chargalg: Fix quick re-attach charger issue.

Martin Bergstrom (2):
  power: ab8500_fg: Report unscaled capacity
  power: ab8500_charger: Limit USB charger current

Martin Bergström (1):
  power: ab8500_fg: Goto INIT_RECOVERY when charger removed

Martin Sjoblom (1):
  power: ab8500_charger: Prevent auto drop of VBUS

Mathieu J. Poirier (4):
  power: Harmonising platform data declaration/handling
  power: Cancelling status charging notification.
  power: ab8500: Re-alignment with internal developement.
  power: ab8500_fg: Moving structure definitions to header file

Michel JAOUEN (2):
  power: ab8500: adaptation to ab version
  power: sysfs interface update

Nicolas Guion (1):
  power: ab8500 - Accessing Autopower register fails

Paer-Olof Haakansson (3):
  power: ab8500_bm: Rename the power_loss function
  power: Overflow in current calculation
  power: u8500_charger: Delay for USB enumeration

Philippe Langlais (1):
  power: ab8500: bm: movimg back to ab8500 platform data managment

Rajkumar Kasirajan (1):
  power: ab8500_fg: fix to use correct battery charge full design

Rickard Andersson (1):
  power: ab8500_fg: balance IRQ enable

Rikard Olsson (1):
  power: ab8500_fg: add power cut feature for ab8505

Rupesh Kumar (3):
  power: l9540: Charge only mode fixes
  power: ab8500: defer btemp filtering while init
  power: ab8500 : quick re-attach for ext charger

Yang QU (1):
  power: add backup battery charge voltages.

pender01 (1):
  power: ab8500_fg: Round capacity output

 drivers/mfd/ab8500-core.c |6 +
 drivers/power/Kconfig |7 -
 drivers/power/ab8500_btemp.c  |  165 +++--
 drivers/power/ab8500_charger.c| 1410 +++--
 drivers/power/ab8500_fg.c | 1085 +--
 drivers/power/ab8500_fg.h |  201 
 drivers/power/abx500_chargalg.c   |  333 ++--
 include/linux/mfd/abx500.h|   30 +-
 include/linux/mfd/abx500/ab8500-bm.h  |   47 +-
 include/linux/mfd/abx500/ab8500.h |   22 +-
 include/linux/mfd/abx500/ux500_chargalg.h |8 +
 11 files changed, 2607 insertions(+), 707 deletions(-)
 create mode 100644 drivers/power/ab8500_fg.h
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 05/57] power: ab8500_bm: Rename the power_loss function

2012-09-25 Thread mathieu . poirier
From: Paer-Olof Haakansson 

Rename the ab8500_power_loss_handling function
to a more describing name ab8500_enable_disable_sw_fallback

Signed-off-by: Robert Marklund 
Signed-off-by: Paer-Olof Haakansson 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Par-Olof HAKANSSON 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_charger.c |   23 +++
 1 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 22076f5..a7d0c3a 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -268,20 +268,19 @@ static enum power_supply_property 
ab8500_charger_usb_props[] = {
POWER_SUPPLY_PROP_CURRENT_NOW,
 };
 
-/**
- * ab8500_power_loss_handling - set how we handle powerloss.
- * @di:pointer to the ab8500_charger structure
- *
- * Magic nummbers are from STE HW department.
+/*
+ * Function for enabling and disabling sw fallback mode
+ * should always be disabled when no charger is connected.
  */
-static void ab8500_power_loss_handling(struct ab8500_charger *di)
+static void ab8500_enable_disable_sw_fallback(struct ab8500_charger *di,
+   bool fallback)
 {
u8 reg;
int ret;
 
-   dev_dbg(di->dev, "Autopower : %d\n", di->autopower);
+   dev_dbg(di->dev, "SW Fallback: %d\n", fallback);
 
-   /* read the autopower register */
+   /* read the register containing fallback bit */
ret = abx500_get_register_interruptible(di->dev, 0x15, 0x00, ®);
if (ret) {
dev_err(di->dev, "%d write failed\n", __LINE__);
@@ -295,12 +294,12 @@ static void ab8500_power_loss_handling(struct 
ab8500_charger *di)
return;
}
 
-   if (di->autopower)
+   if (fallback)
reg |= 0x8;
else
reg &= ~0x8;
 
-   /* write back the changed value to autopower reg */
+   /* write back the changed fallback bit value to register */
ret = abx500_set_register_interruptible(di->dev, 0x15, 0x00, reg);
if (ret) {
dev_err(di->dev, "%d write failed\n", __LINE__);
@@ -330,12 +329,12 @@ static void ab8500_power_supply_changed(struct 
ab8500_charger *di,
!di->ac.charger_connected &&
di->autopower) {
di->autopower = false;
-   ab8500_power_loss_handling(di);
+   ab8500_enable_disable_sw_fallback(di, false);
} else if (!di->autopower &&
   (di->ac.charger_connected ||
di->usb.charger_connected)) {
di->autopower = true;
-   ab8500_power_loss_handling(di);
+   ab8500_enable_disable_sw_fallback(di, true);
}
}
power_supply_changed(psy);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 03/57] power: ab8500_btemp: Detect battery type in workqueue

2012-09-25 Thread mathieu . poirier
From: Jonas Aaberg 

Detect battery type in work queue instead of probe.
This reduces the system boot time with 1.5s

Signed-off-by: Jonas Aaberg 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Karl KOMIEROWSKI 
---
 drivers/power/ab8500_btemp.c |   15 +++
 1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index bba3cca..94a3ee8 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -83,6 +83,7 @@ struct ab8500_btemp_ranges {
  * @btemp_ranges:  Battery temperature range structure
  * @btemp_wq:  Work queue for measuring the temperature periodically
  * @btemp_periodic_work:   Work for measuring the temperature periodically
+ * @initialized:   True if battery id read.
  */
 struct ab8500_btemp {
struct device *dev;
@@ -100,6 +101,7 @@ struct ab8500_btemp {
struct ab8500_btemp_ranges btemp_ranges;
struct workqueue_struct *btemp_wq;
struct delayed_work btemp_periodic_work;
+   bool initialized;
 };
 
 /* BTEMP power supply properties */
@@ -569,6 +571,13 @@ static void ab8500_btemp_periodic_work(struct work_struct 
*work)
struct ab8500_btemp *di = container_of(work,
struct ab8500_btemp, btemp_periodic_work.work);
 
+   if (!di->initialized) {
+   di->initialized = true;
+   /* Identify the battery */
+   if (ab8500_btemp_id(di) < 0)
+   dev_warn(di->dev, "failed to identify the battery\n");
+   }
+
di->bat_temp = ab8500_btemp_measure_temp(di);
 
if (di->bat_temp != di->prev_bat_temp) {
@@ -981,6 +990,8 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
di->parent = dev_get_drvdata(pdev->dev.parent);
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
 
+   di->initialized = false;
+
/* get btemp specific platform data */
di->pdata = plat_data->btemp;
if (!di->pdata) {
@@ -1021,10 +1032,6 @@ static int __devinit ab8500_btemp_probe(struct 
platform_device *pdev)
INIT_DELAYED_WORK_DEFERRABLE(&di->btemp_periodic_work,
ab8500_btemp_periodic_work);
 
-   /* Identify the battery */
-   if (ab8500_btemp_id(di) < 0)
-   dev_warn(di->dev, "failed to identify the battery\n");
-
/* Set BTEMP thermal limits. Low and Med are fixed */
di->btemp_ranges.btemp_low_limit = BTEMP_THERMAL_LOW_LIMIT;
di->btemp_ranges.btemp_med_limit = BTEMP_THERMAL_MED_LIMIT;
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 02/57] power: ab8500_bm: Don't clear the CCMuxOffset bit

2012-09-25 Thread mathieu . poirier
From: Kalle Komierowski 

The CCMuxOffset bit is not kept set, this will force the columb counter
of the AB8500 to use the measure offset calibration.
This should increase the accuracy of the fuel gauge.

Signed-off-by: Kalle Komierowski 
Signed-off-by: Marcus Cooper 
Signed-off-by: Mathieu Poirier 
Reviewed-by: Jonas ABERG 
---
 drivers/power/ab8500_fg.c |8 
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index bf02225..af792a8 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -485,8 +485,9 @@ static int ab8500_fg_coulomb_counter(struct ab8500_fg *di, 
bool enable)
di->flags.fg_enabled = true;
} else {
/* Clear any pending read requests */
-   ret = abx500_set_register_interruptible(di->dev,
-   AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG, 0);
+   ret = abx500_mask_and_set_register_interruptible(di->dev,
+   AB8500_GAS_GAUGE, AB8500_GASG_CC_CTRL_REG,
+   (RESET_ACCU | READ_REQ), 0);
if (ret)
goto cc_err;
 
@@ -1404,8 +1405,7 @@ static void ab8500_fg_algorithm_discharging(struct 
ab8500_fg *di)
sleep_time = di->bat->fg_params->init_timer;
 
/* Discard the first [x] seconds */
-   if (di->init_cnt >
-   di->bat->fg_params->init_discard_time) {
+   if (di->init_cnt > di->bat->fg_params->init_discard_time) {
ab8500_fg_calc_cap_discharge_voltage(di, true);
 
ab8500_fg_check_capacity_limits(di, true);
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-10-20 Thread Mathieu Poirier
On 12-10-16 09:35 PM, Arve Hjønnevåg wrote:
> On Fri, Oct 5, 2012 at 12:48 PM, Mathieu Poirier
>  wrote:
>> On 12-10-05 12:16 PM, Dmitry Torokhov wrote:
>>> On Fri, Oct 05, 2012 at 11:59:29AM -0600, mathieu.poir...@linaro.org wrote:
>>>> From: "Mathieu J. Poirier" 
>>>>
>>>> Andrew,
>>>>
>>>> After requesting a number of changes that, to my understanding
>>>> have been implemented, I have not been able to get the attention
>>>> of the subsystem maintainer on this patch.
>>>>
>>>> If there are still issues, I'm open to making changes but I want
>>>> to make sure it doesn't get forgotten.  If there no objections,
>>>> would you consider queuint it ?
>>>
>>> Mathieu,
>>>
>>> I have the same objection as before: using platform device solely for
>>> the purpose of passing some data from board code to the driver. Surely
>>> there are other ways of passing this bit of data... What about, for
>>> example, making it an empty weak symbol so that board code could
>>> override it with strong one?
>>
>> Thanks for the comments - I will implement a weak function in the
>> keyreset driver.
>>
> 
> A weak symbol does not work. A single kernel can support multiple
> devices that have unique reset key combinations.
> 

I'm afraid Arve has a point here...  His comment about supporting
multiple combinations got me thinking and forced me to dive back in the
code.

The original keyreset driver can indeed be instantiated multiple times
while the sysrq driver is a one instance model.  In its current
implementation the keyreset extension can only support one reset sequence.

But does a system realistically need to support more than one reset
sequence ?

If so then I can enhance the keyreset extension of the sysrq driver but
that will also mean, as stated by Arve, that we will need to keep the
platform data.  On the flip side it is deemed sufficient to support a
single reset sequence then I'll implement the weak symbol method.

The subject is up for debate, please chime in with your opinion.

Mathieu.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v4] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-11-11 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.

Redefining the '__weak sysrq_keyreset_get_params' function is required
to trigger the feature.  Alternatively keys can be passed to the
driver via the "/sys/module/sysrq" interface.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Cc: a...@lxorguk.ukuu.org.uk
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  303 +
 include/linux/sysrq.h |2 +
 2 files changed, 305 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..da4f538 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,14 +41,29 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
 
+#define KEY_RESET_MAX  20 /* how  many is enough ? */
+int keyreset_param[KEY_RESET_MAX];
+struct mutex sysrq_mutex;
+static struct sysrq_state *sysrq_handle;
+
 /* Whether we react on sysrq keys or just ignore them */
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +585,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +627,80 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   mutex_lock(&sysrq_mutex);
+
+   /* Is the code of interest to us */
+   if (!test_bit(code, state->keybit)) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &&
+   state->key_down_ctn == state->key_down_target) {
+   state->restart_disabled = 1;
+   if (atomic_read(&restart_requested))
+   panic("keyboard reset failed, %d - panic\n",
+atomic_read(&restart_requested));
+   if (state->reset_fn) {
+   ret = state->reset_fn();
+   atomic_set(&restart_requested, ret);
+   } else {
+   pr_info("keyboard reset\n");
+   schedule_work(&restart_work);
+   atomic_inc(&restart_requested);
+   }
+   }
+
+   mutex_unlock(&sysrq_mutex);
+
+   /* no need to suppress keyreset characters */
+   state->a

Re: Out-of-bound access in sysrq

2013-03-28 Thread Mathieu Poirier
On 13-03-28 04:34 AM, Jiri Slaby wrote:
> Guys,
> 
> how is this supposed to work?
> 
> #define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */
> static unsigned short sysrq_reset_seq[SYSRQ_KEY_RESET_MAX];
> ...
> unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
> ...
> static inline void sysrq_register_handler(void)
> {
> ...
> for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
> key = platform_sysrq_reset_seq[i];
> if (key == KEY_RESERVED || key > KEY_MAX)
> ...
> 
> 
> 
> 
> i runs from 0 to 19 incl., but platform_sysrq_reset_seq, if not
> overriden, is of size 1, so?
> 
> thanks,
> 

Unless I'm missing something, 'i' won't go higher than '0' since the
first element of platform_sysrq_reset_seq is set to KEY_RESERVED and in
such case the 'break' is executed.


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-08-27 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.  A platform device that specify a
reset key-combo should be added to the board file to trigger the
feature.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  159 +
 include/linux/sysrq.h |8 +++
 2 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..6cf5531 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,6 +41,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
@@ -49,6 +52,11 @@
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +578,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +620,92 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+
+static int sysrq_probe(struct platform_device *pdev)
+{
+   struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+
+   /* No sequence of keys to trigger on,
+* assuming default sysRQ behavior.
+*/
+   if (pdata) {
+   atomic_set(&restart_requested, 0);
+   sysrq_handler.private = pdata;
+   } else
+   sysrq_handler.private = NULL;
+
+   /* FETCH DT INFO HERE */
+
+   return 0;
+
+}
+
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   /* Is the code is of interestest to us */
+   if (!test_bit(code, state->keybit))
+   return processed;
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value)
+   return processed;
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &&
+   state->key_down_ctn == state->key_down_target) {
+   state->restart_disabled = 1;
+   if (atomic_read(&restart_requested))
+   panic("keyboard reset failed, %d - panic\n",
+atomic_read(&restart_requested));
+   if (state->reset_fn) {
+   ret = state->reset_fn();
+   atomic_set(&restart_requested, ret);
+   } else {
+   pr_info("keyboard reset\n");
+   schedule_work(&restart_work);
+   atomic_inc(&restart_requested);
+   }
+   }
+
+   /* no need to suppress keyreset characters */
+   state->active = false;
+
+   return processed;
+}
+
 st

[PATCH v3] drivers/tty: Folding Android's keyreset driver in sysRQ

2012-09-16 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.

A platform device that specify a reset key-combo should be added to
the board file to trigger the feature.  Alternatively keys can be
passed to the driver via the "/sys/module/sysrq" interface.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  302 +
 include/linux/sysrq.h |8 ++
 2 files changed, 310 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..41122a7 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,14 +41,30 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
+#include 
+
+#define KEY_DOWN_MAX   20 /* how  many is enough ? */
+int keyreset_param[KEY_DOWN_MAX];
+struct mutex sysrq_mutex;
+static struct sysrq_state *sysrq_handle;
 
 /* Whether we react on sysrq keys or just ignore them */
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +586,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +628,101 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+
+static int sysrq_probe(struct platform_device *pdev)
+{
+   struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+
+   /*
+* No sequence of keys to trigger on,
+* assuming default sysRQ behavior.
+*/
+   if (pdata) {
+   atomic_set(&restart_requested, 0);
+   sysrq_handler.private = pdata;
+   } else
+   sysrq_handler.private = NULL;
+
+   /* FETCH DT INFO HERE */
+
+   return 0;
+
+}
+
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   mutex_lock(&sysrq_mutex);
+
+   /* Is the code of interest to us */
+   if (!test_bit(code, state->keybit)) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value) {
+   mutex_unlock(&sysrq_mutex);
+   return processed;
+   }
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &&
+   state->key_down_ctn == state->key_down_target) {
+   state->restart_disabled = 1;
+   if (atomic_read(&restart_requested))
+   panic("keyboard reset failed, %d - panic\n",
+atomic_read(&restart_requested));
+

[PATCH] [RFC]: drivers/tty: Folding Android's keyreset driver in sysRQ

2012-08-16 Thread mathieu . poirier
From: "Mathieu J. Poirier" 

This patch adds keyreset functionality to the sysrq driver. It
allows certain button/key combinations to be used in order to
trigger device resets.

The first time the key-combo is detected a work function that syncs
the filesystems is scheduled and the kernel rebooted. If all the keys
are released and then pressed again, it calls panic. Reboot on panic
should be set for this to work.  A platform device that specify a
reset key-combo should be added to the board file to trigger the
feature.

This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.  It is sent out as an initial
draft and comments are welcomed.

In the design most of the original author's code has been added
alongside the sysrq functionality, taking great care not to
remove or constrain functionality people might currently be using.

The keyreset platform data and driver name were kept intact to
minimize disruption on products that already instantiate the
keyreset driver.

Cc: a...@android.com
Cc: kernel-t...@android.com
Cc: dmitry.torok...@gmail.com
Cc: john.stu...@linaro.org
Signed-off-by: Mathieu Poirier 
---
 drivers/tty/sysrq.c   |  159 +
 include/linux/sysrq.h |8 +++
 2 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 05728894..c2b869d 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,6 +41,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include 
 #include 
@@ -49,6 +52,11 @@
 static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
 static bool __read_mostly sysrq_always_enabled;
 
+static struct input_handler sysrq_handler;
+
+/* Keep track of what has been called */
+static atomic_t restart_requested;
+
 static bool sysrq_on(void)
 {
return sysrq_enabled || sysrq_always_enabled;
@@ -570,6 +578,15 @@ struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+   unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+   int (*reset_fn)(void);
+   int key_down_target;
+   int key_down_ctn;
+   int key_up_ctn;
+   int keyreset_data;
+   int restart_disabled;
unsigned int alt;
unsigned int alt_use;
bool active;
@@ -603,6 +620,92 @@ static void sysrq_reinject_alt_sysrq(struct work_struct 
*work)
}
 }
 
+
+static int sysrq_probe(struct platform_device *pdev)
+{
+   struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+
+   /* No sequence of keys to trigger on,
+* assuming default sysRQ behavior.
+*/
+   if (pdata) {
+   atomic_set(&restart_requested, 0);
+   sysrq_handler.private = pdata;
+   } else
+   sysrq_handler.private = NULL;
+
+   /* FETCH DT INFO HERE */
+
+   return 0;
+
+}
+
+static void deferred_restart(struct work_struct *dummy)
+{
+   atomic_inc(&restart_requested);
+   sys_sync();
+   atomic_inc(&restart_requested);
+   kernel_restart(NULL);
+}
+static DECLARE_WORK(restart_work, deferred_restart);
+
+static int do_keyreset_event(struct sysrq_state *state,
+unsigned int code, int value)
+{
+   int ret;
+   int processed = 0;
+
+   /* Is the code is of interestest to us */
+   if (!test_bit(code, state->keybit))
+   return processed;
+
+   /* No need to take care of key up events */
+   if (!test_bit(code, state->key) == !value)
+   return processed;
+
+   /* Record new entry */
+   __change_bit(code, state->key);
+
+   processed = 1;
+
+   if (test_bit(code, state->upbit)) {
+   if (value) {
+   state->restart_disabled = 1;
+   state->key_up_ctn++;
+   } else
+   state->key_up_ctn--;
+   } else {
+   if (value)
+   state->key_down_ctn++;
+   else
+   state->key_down_ctn--;
+   }
+
+   if (state->key_down_ctn == 0 && state->key_up_ctn == 0)
+   state->restart_disabled = 0;
+
+   if (value && !state->restart_disabled &&
+   state->key_down_ctn == state->key_down_target) {
+   state->restart_disabled = 1;
+   if (atomic_read(&restart_requested))
+   panic(KERN_ERR "keyboard reset failed, %d - panic\n",
+atomic_read(&restart_requested));
+   if (state->reset_fn) {
+   ret = state->reset_fn();
+

Re: [PATCH 00/57] power: Upgrade to ux500 battery management driver

2012-09-27 Thread Mathieu Poirier
On 12-09-26 09:38 PM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:11:57AM -0600, mathieu.poir...@linaro.org wrote:
>> From: "Mathieu J. Poirier" 
>>
>> This patch set upgrades the current ux500 battery management driver
>> to the latest HW and functionality.
>>
>> Pull request for convenience:
>>
>> The following changes since commit 56d27adcb536b7430d5f8a6240df8ad261eb00bd:
>>
>>   Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile 
>> (2012-09-24 16:17:17 -0700)
>>
>> are available in the git repository at:
>>
>>   git://git.linaro.org/people/mpoirier/linux.git ux500-battery-management
> 
> I reviewed this series before, and all looked quite good overall. But I
> took another look, especially at the patches w/ empty commit messages, and
> there are some issues.
> 
> I tried to write some descriptions myself, but I failed: some changes are
> not obvious to me, so I couldn't write rationale for them. :-/
> 
> Thanks,
> Anton.
> 

Thank you very much for the review.

I am half way through your comments - some I can handle myself, for
others I needed to go back to the original author for clarification.
Another set will follow shortly.

Your time is much appreciated,
Mathieu.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 33/57] power: u8500_charger: Delay for USB enumeration

2012-09-28 Thread Mathieu Poirier
On 12-09-27 01:42 AM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:30AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Paer-Olof Haakansson 
>>
>> If charging is started before USB enumeration of an
>> Accessory Charger Adapter has finished, the AB8500 will
>> generate a VBUS_ERROR. This in turn results in timeouts
>> and delays the enumeration with around 15 seconds.
>> This patch delays the charging and then ramps currents
>> slowly to avoid VBUS errors. The delay allows the enumeration
>> to have finished before charging is turned on.
>>
>> Signed-off-by: Martin Sjoblom 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Jonas ABERG 
>> ---
> [...]
>> @@ -264,17 +275,19 @@ struct ab8500_charger {
>>  struct ab8500_charger_info usb;
>>  struct regulator *regu;
>>  struct workqueue_struct *charger_wq;
>> +struct mutex usb_ipt_crnt_lock;
>>  struct delayed_work check_vbat_work;
>>  struct delayed_work check_hw_failure_work;
>>  struct delayed_work check_usbchgnotok_work;
>>  struct delayed_work kick_wd_work;
>> +struct delayed_work usb_state_changed_work;
>>  struct delayed_work attach_work;
>>  struct delayed_work ac_charger_attached_work;
>>  struct delayed_work usb_charger_attached_work;
>> +struct delayed_work vbus_drop_end_work;
>>  struct work_struct ac_work;
>>  struct work_struct detect_usb_type_work;
>>  struct work_struct usb_link_status_work;
>> -struct work_struct usb_state_changed_work;
> 
> This just moves line around. Doesn't belong to this patch.

This is moving 'usb_state_changed_work' from type 'struct work_struct'
to 'struct delayed_work'.  Is it that you want to see the change on the
same line rather than two different lines ?

> 
>>  struct work_struct check_main_thermal_prot_work;
>>  struct work_struct check_usb_thermal_prot_work;
>>  struct usb_phy *usb_phy;
>> @@ -560,6 +573,7 @@ static int ab8500_charger_usb_cv(struct ab8500_charger 
>> *di)
>>  /**
>>   * ab8500_charger_detect_chargers() - Detect the connected chargers
>>   * @di: pointer to the ab8500_charger structure
>> + * @probe: if probe, don't delay and wait for HW
>>   *
>>   * Returns the type of charger connected.
>>   * For USB it will not mean we can actually charge from it
>> @@ -570,10 +584,10 @@ static int ab8500_charger_usb_cv(struct ab8500_charger 
>> *di)
>>   * Returns an integer value, that means,
>>   * NO_PW_CONN  no power supply is connected
>>   * AC_PW_CONN  if the AC power supply is connected
>> - * USB_PW_CONN  if the USB power supply is connected
>> + * USB_PW_CONN  if the USB power supply is connected
> 
> Cosmetic change... doesn't belong to this patch, I guess.
> 
>>   * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
>>   */
>> -static int ab8500_charger_detect_chargers(struct ab8500_charger *di)
>> +static int ab8500_charger_detect_chargers(struct ab8500_charger *di, bool 
>> probe)
>>  {
>>  int result = NO_PW_CONN;
>>  int ret;
>> @@ -591,6 +605,15 @@ static int ab8500_charger_detect_chargers(struct 
>> ab8500_charger *di)
>>  result = AC_PW_CONN;
>>  
>>  /* Check for USB charger */
>> +if (!probe) {
>> +/*
>> + * AB8500 says VBUS_DET_DBNC1 & VBUS_DET_DBNC100
>> + * when disconnecting ACA even though no
>> + * charger was connected. Try waiting a little
>> + * longer than the 100 ms of VBUS_DET_DBNC100...
>> + */
>> +msleep(110);
>> +}
>>  ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
>>  AB8500_CH_USBCH_STAT1_REG, &val);
>>  if (ret < 0) {
>> @@ -598,6 +621,9 @@ static int ab8500_charger_detect_chargers(struct 
>> ab8500_charger *di)
>>  return ret;
>>  }
>>  
>> +dev_dbg(di->dev,
>> +"%s AB8500_CH_USBCH_STAT1_REG %x\n", __func__, val);
>> +
>>  if ((val & VBUS_DET_DBNC1) && (val & VBUS_DET_DBNC100))
>>  result |= USB_PW_CONN;
>>  
>> @@ -620,33 +646,47 @@ static int ab8500_charger_max_usb_curr(struct 
>> ab8500_charger *di,
>>  
>>  di->usb_device_is_unrecognised = false;
>>  
>> +/*
>> + * Platform only supports USB 2.0.
>> + * This means that charging c

Re: [PATCH 17/57] power: ab8500_bm: Added support for BATT_OVV

2012-09-28 Thread Mathieu Poirier
On 12-09-26 09:36 PM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:14AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Hakan Berg 
>>
>> Add support for the battery over-voltage situation
>>
>> Signed-off-by: Hakan Berg 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Karl KOMIEROWSKI 
>> ---
>>  drivers/power/ab8500_fg.c |   32 
>>  1 files changed, 16 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
>> index c4d9307..8507254 100644
>> --- a/drivers/power/ab8500_fg.c
>> +++ b/drivers/power/ab8500_fg.c
>> @@ -1842,24 +1842,26 @@ static void ab8500_fg_check_hw_failure_work(struct 
>> work_struct *work)
>>   * If we have had a battery over-voltage situation,
>>   * check ovv-bit to see if it should be reset.
>>   */
>> -if (di->flags.bat_ovv) {
>> -ret = abx500_get_register_interruptible(di->dev,
>> -AB8500_CHARGER, AB8500_CH_STAT_REG,
>> -®_value);
>> -if (ret < 0) {
>> -dev_err(di->dev, "%s ab8500 read failed\n", __func__);
>> -return;
>> -}
>> -if ((reg_value & BATT_OVV) != BATT_OVV) {
>> -dev_dbg(di->dev, "Battery recovered from OVV\n");
>> -di->flags.bat_ovv = false;
>> +ret = abx500_get_register_interruptible(di->dev,
>> +AB8500_CHARGER, AB8500_CH_STAT_REG,
>> +®_value);
>> +if (ret < 0) {
>> +dev_err(di->dev, "%s ab8500 read failed\n", __func__);
>> +return;
>> +}
>> +if ((reg_value & BATT_OVV) == BATT_OVV) {
>> +if (!di->flags.bat_ovv) {
>> +dev_dbg(di->dev, "Battery OVV\n");
>> +di->flags.bat_ovv = true;
>>  power_supply_changed(&di->fg_psy);
>> -return;
>>  }
>> -
>>  /* Not yet recovered from ovv, reschedule this test */
>>  queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work,
>> -   round_jiffies(HZ));
>> +HZ);
> 
> Why this change? I.e. round_jiffies(HZ) -> HZ?
> 
> Yes, it seems like round_jiffies(HZ) is not needed since HZ itself is a
> full second.. But the change itself does not belong to this patch.

I agree with your point of view.  How do we fix it now ?  Do you think
it's worth crafting a one-line patch ?

> 
>> +} else {
>> +dev_dbg(di->dev, "Battery recovered from OVV\n");
>> +di->flags.bat_ovv = false;
>> +power_supply_changed(&di->fg_psy);
>>  }
>>  }
>>  
>> @@ -2039,8 +2041,6 @@ static irqreturn_t ab8500_fg_batt_ovv_handler(int irq, 
>> void *_di)
>>  struct ab8500_fg *di = _di;
>>  
>>  dev_dbg(di->dev, "Battery OVV\n");
>> -di->flags.bat_ovv = true;
>> -power_supply_changed(&di->fg_psy);
>>  
>>  /* Schedule a new HW failure check */
>>  queue_delayed_work(di->fg_wq, &di->fg_check_hw_failure_work, 0);
>> -- 
>> 1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 18/57] power: Add sysfs interfaces for capacity

2012-09-28 Thread Mathieu Poirier
On 12-09-27 01:08 AM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:15AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Daniel WILLERUD 
>>
>> Switchable depending on whether capacity scaling is enabled
>>
>> Signed-off-by: Marcus Cooper 
>> Signed-off-by: Daniel WILLERUD 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Jonas ABERG 
>> ---
>>  drivers/power/ab8500_fg.c |   57 
>> -
>>  1 files changed, 56 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
>> index 8507254..46010ec 100644
>> --- a/drivers/power/ab8500_fg.c
>> +++ b/drivers/power/ab8500_fg.c
>> @@ -266,7 +266,6 @@ static enum power_supply_property ab8500_fg_props[] = {
>>  POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
>>  POWER_SUPPLY_PROP_CHARGE_FULL,
>>  POWER_SUPPLY_PROP_CHARGE_NOW,
>> -POWER_SUPPLY_PROP_CAPACITY,
> [...]
>> +static struct device_attribute ab8500_fg_sysfs_psy_attrs[] = {
>> +__ATTR(capacity, S_IRUGO, ab8500_show_capacity, NULL),
>> +};
> 
> I don't understand the rationale behind this patch. Why remove normal
> power supply property, and make your own with the same name? Something
> isn't right...

The similarity in the naming convention it a coincidence here.  In one
case it's a enum and the other sysfs attribute.  Could you expand on
your suspicions ?

> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 27/57] power: sysfs interface update

2012-09-28 Thread Mathieu Poirier
On 12-09-27 01:20 AM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:24AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Michel JAOUEN 
>>
>> Add new sysfs interface to get current charge status
>>
>> Signed-off-by: Michel JAOUEN 
>> Signed-off-by: Loic Pallardy 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Marcus COOPER 
>> Reviewed-by: Olivier CLERGEAUD 
>> Reviewed-by: Jonas ABERG 
>> ---
>>  drivers/power/ab8500_charger.c  |3 +++
>>  drivers/power/abx500_chargalg.c |   24 +++-
>>  2 files changed, 26 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
>> index 4129599..0a781a0 100644
>> --- a/drivers/power/ab8500_charger.c
>> +++ b/drivers/power/ab8500_charger.c
>> @@ -2759,6 +2759,9 @@ static int ab8500_charger_usb_notifier_call(struct 
>> notifier_block *nb,
>>  enum ab8500_usb_state bm_usb_state;
>>  unsigned mA = *((unsigned *)power);
>>  
>> +if (di == NULL)
>> +return NOTIFY_DONE;
>> +
> 
> I'd write !di.

Not sure I agree with you here.  If di is NULL there is nothing to work
with and as such, exit.

> 
> [...]
>> +static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
>> +struct attribute *attr, char *buf)
>> +{
>> +struct abx500_chargalg *di = container_of(kobj,
>> +struct abx500_chargalg, chargalg_kobject);
>> +
>> +if ((di->susp_status.ac_suspended == true) &&
>> +(di->susp_status.usb_suspended == true))
>> +return sprintf(buf, "0\n");
>> +else
>> +return sprintf(buf, "1\n");
> 
> just
> 
> return sprintf(buf, "%d\n", di->susp_status.ac_suspended &&
>   di->susp_status.usb_suspended);

Much cleaner yes.

> 
>> +}
>> +
>>  /* Exposure to the sysfs interface */
>>  
>>  /**
>> @@ -1749,7 +1770,7 @@ static ssize_t abx500_chargalg_sysfs_charger(struct 
>> kobject *kobj,
>>  static struct attribute abx500_chargalg_en_charger = \
>>  {
>>  .name = "chargalg",
>> -.mode = S_IWUGO,
>> +.mode = S_IRUGO | S_IWUSR,
>>  };
>>  
>>  static struct attribute *abx500_chargalg_chg[] = {
>> @@ -1758,6 +1779,7 @@ static struct attribute *abx500_chargalg_chg[] = {
>>  };
>>  
>>  static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
>> +.show = abx500_chargalg_sysfs_show,
>>  .store = abx500_chargalg_sysfs_charger,
>>  };
>>  
>> -- 
>> 1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 30/57] power: ab8500: Flush & sync all works

2012-09-28 Thread Mathieu Poirier
On 12-09-27 01:23 AM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:27AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Jonas Aaberg 
>>
>> Flush and sync all workqueues at suspend to avoid
>> that we suspend in the middle of a work.
>>
>> Signed-off-by: Jonas Aaberg 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Marcus COOPER 
>> ---
>>  drivers/power/ab8500_charger.c |   11 +++
>>  drivers/power/ab8500_fg.c  |5 +
>>  2 files changed, 16 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
>> index ee5ad7b..071c7c2 100644
>> --- a/drivers/power/ab8500_charger.c
>> +++ b/drivers/power/ab8500_charger.c
>> @@ -2862,6 +2862,17 @@ static int ab8500_charger_suspend(struct 
>> platform_device *pdev,
>>  if (delayed_work_pending(&di->check_hw_failure_work))
>>  cancel_delayed_work(&di->check_hw_failure_work);
>>  
>> +flush_delayed_work_sync(&di->attach_work);
>> +flush_delayed_work_sync(&di->usb_charger_attached_work);
>> +flush_delayed_work_sync(&di->ac_charger_attached_work);
>> +flush_delayed_work_sync(&di->check_usbchgnotok_work);
>> +flush_delayed_work_sync(&di->check_vbat_work);
>> +flush_delayed_work_sync(&di->kick_wd_work);
>> +
>> +flush_work_sync(&di->usb_link_status_work);
>> +flush_work_sync(&di->ac_work);
>> +flush_work_sync(&di->detect_usb_type_work);
> 
> I belive each of these have to be added by the patches that add the
> appropriate work structs. But really, it's better to avoid these many
> delayed work.

Agreed - on the flip side they were added over multiple patches spanning
many centuries.  Tracking all this work down would be impossible as
history was re-written many time over.  What would you like to see
happening here ?

> 
>>  return 0;
>>  }
>>  #else
>> diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
>> index e7a0e1f..0e71e7e 100644
>> --- a/drivers/power/ab8500_fg.c
>> +++ b/drivers/power/ab8500_fg.c
>> @@ -2626,6 +2626,11 @@ static int ab8500_fg_suspend(struct platform_device 
>> *pdev,
>>  struct ab8500_fg *di = platform_get_drvdata(pdev);
>>  
>>  flush_delayed_work_sync(&di->fg_periodic_work);
>> +flush_work_sync(&di->fg_work);
>> +flush_work_sync(&di->fg_acc_cur_work);
>> +flush_delayed_work_sync(&di->fg_reinit_work);
>> +flush_delayed_work_sync(&di->fg_low_bat_work);
>> +flush_delayed_work_sync(&di->fg_check_hw_failure_work);
>>  
>>  /*
>>   * If the FG is enabled we will disable it before going to suspend
>> -- 
>> 1.7.5.4
>>
>>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 38/57] power: l9540: Charge only mode fixes

2012-09-28 Thread Mathieu Poirier
On 12-09-27 06:27 PM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:35AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Rupesh Kumar 
>>
>> Fix for: charging not getting enabled in
>> charge only mode by external charger.
> 
> Subject says l9540.. what is this?
> 
>> Signed-off-by: Rupesh Kumar 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Marcus COOPER 
>> Reviewed-by: Michel JAOUEN 
>> Reviewed-by: Philippe LANGLAIS 
>> Reviewed-by: Philippe LANGLAIS 
>> ---
>>  drivers/power/ab8500_charger.c|   42 
>> +
>>  drivers/power/abx500_chargalg.c   |   14 +
>>  include/linux/mfd/abx500/ux500_chargalg.h |2 +
>>  3 files changed, 58 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
>> index 70e7c5e..ebeb068 100644
>> --- a/drivers/power/ab8500_charger.c
>> +++ b/drivers/power/ab8500_charger.c
>> @@ -15,6 +15,7 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>  #include 
>>  #include 
>>  #include 
>> @@ -94,6 +95,10 @@
>>  #define AB8500_SW_CONTROL_FALLBACK  0x03
>>  /* Wait for enumeration before charging in us */
>>  #define WAIT_ACA_RID_ENUMERATION(5 * 1000)
>> +/*External charger control*/
>> +#define AB8500_SYS_CHARGER_CONTROL_REG  0x52
>> +#define EXTERNAL_CHARGER_DISABLE_REG_VAL0x03
>> +#define EXTERNAL_CHARGER_ENABLE_REG_VAL 0x07
>>  
>>  /* UsbLineStatus register - usb types */
>>  enum ab8500_charger_link_status {
>> @@ -1672,6 +1677,29 @@ static int ab8500_charger_usb_en(struct ux500_charger 
>> *charger,
>>  return ret;
>>  }
>>  
>> +static int ab8500_external_charger_prepare(struct notifier_block 
>> *charger_nb,
>> +unsigned long event, void *data)
>> +{
>> +int ret;
>> +struct device *dev = data;
> 
> Need an empty line here.
> 
>> +/*Toggle External charger control pin*/
> 
> Spaces after /* and before */.
> 
>> +ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
>> +  AB8500_SYS_CHARGER_CONTROL_REG,
>> +  EXTERNAL_CHARGER_DISABLE_REG_VAL);
>> +if (ret < 0) {
>> +dev_err(dev, "write reg failed %d\n", ret);
>> +goto out;
> 
> No need for goto.
> 
>> +}
>> +ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
>> +  AB8500_SYS_CHARGER_CONTROL_REG,
>> +  EXTERNAL_CHARGER_ENABLE_REG_VAL);
>> +if (ret < 0)
>> +dev_err(dev, "Write reg failed %d\n", ret);
>> +
>> +out:
>> +return ret;
>> +}
>> +
>>  /**
>>   * ab8500_charger_usb_check_enable() - enable usb charging
>>   * @charger:pointer to the ux500_charger structure
>> @@ -3201,6 +3229,10 @@ static int ab8500_charger_suspend(struct 
>> platform_device *pdev,
>>  #define ab8500_charger_resume   NULL
>>  #endif
>>  
>> +static struct notifier_block charger_nb = {
>> +.notifier_call = ab8500_external_charger_prepare,
>> +};
>> +
>>  static int __devexit ab8500_charger_remove(struct platform_device *pdev)
>>  {
>>  struct ab8500_charger *di = platform_get_drvdata(pdev);
>> @@ -3233,6 +3265,11 @@ static int __devexit ab8500_charger_remove(struct 
>> platform_device *pdev)
>>  /* Delete the work queue */
>>  destroy_workqueue(di->charger_wq);
>>  
>> +/*Unregister external charger enable notifier*/
> 
> Spaces.
> 
>> +if (!di->ac_chg.enabled)
>> +blocking_notifier_chain_unregister(
>> +&charger_notifier_list, &charger_nb);
>> +
>>  flush_scheduled_work();
>>  if (di->usb_chg.enabled)
>>  power_supply_unregister(&di->usb_chg.psy);
>> @@ -3307,6 +3344,11 @@ static int __devinit ab8500_charger_probe(struct 
>> platform_device *pdev)
>>  di->ac_chg.enabled = di->pdata->ac_enabled;
>>  di->ac_chg.external = false;
>>  
>> +/*notifier for external charger enabling*/
> 
> Spaces.
> 
>> +if (!di->ac_chg.enabled)
>> +blocking_notifier_chain_register(
>> +&charger_notifier_list, &charger_nb);
>> +
>>  /* USB supply */
>>

Re: [PATCH 52/57] power: abx500_chargalg: Use hrtimer

2012-09-28 Thread Mathieu Poirier
On 12-09-27 08:47 PM, Anton Vorontsov wrote:
> On Tue, Sep 25, 2012 at 10:12:49AM -0600, mathieu.poir...@linaro.org wrote:
>> From: Hakan Berg 
>>
>> Timers used for charging safety and maintenance must work even when
>> CPU is power collapsed. By using hrtimers with realtime clock, system
>> is able to trigger an alarm that wakes the CPU up and make it possible
>> to handle the event.
>>
>> Allow a little slack of 5 minutes to the hrtimers to allow CPU to be
>> waked up in a more optimal power saving way. A 5 minute delay to
>> time out timers on hours does not impact on safety.
>>
>> Signed-off-by: Hakan Berg 
>> Signed-off-by: Mathieu Poirier 
>> Reviewed-by: Mian Yousaf KAUKAB 
>> ---
>>  drivers/power/abx500_chargalg.c |   94 
>> ++-
>>  1 files changed, 53 insertions(+), 41 deletions(-)
>>
>> diff --git a/drivers/power/abx500_chargalg.c 
>> b/drivers/power/abx500_chargalg.c
>> index 636d970..c8849af 100644
>> --- a/drivers/power/abx500_chargalg.c
>> +++ b/drivers/power/abx500_chargalg.c
>> @@ -1,5 +1,6 @@
>>  /*
>>   * Copyright (C) ST-Ericsson SA 2012
>> + * Copyright (c) 2012 Sony Mobile Communications AB
>>   *
>>   * Charging algorithm driver for abx500 variants
>>   *
>> @@ -8,11 +9,13 @@
>>   *  Johan Palsson 
>>   *  Karl Komierowski 
>>   *  Arun R Murthy 
>> + *  Imre Sunyi 
>>   */
>>  
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>>  #include 
>>  #include 
>>  #include 
>> @@ -32,6 +35,12 @@
>>  /* End-of-charge criteria counter */
>>  #define EOC_COND_CNT10
>>  
>> +/* One hour expressed in seconds */
>> +#define ONE_HOUR_IN_SECONDS 3600
>> +
>> +/* Five minutes expressed in seconds */
>> +#define FIVE_MINUTES_IN_SECONDS 300
>> +
>>  #define to_abx500_chargalg_device_info(x) container_of((x), \
>>  struct abx500_chargalg, chargalg_psy);
>>  
>> @@ -245,8 +254,8 @@ struct abx500_chargalg {
>>  struct delayed_work chargalg_periodic_work;
>>  struct delayed_work chargalg_wd_work;
>>  struct work_struct chargalg_work;
>> -struct timer_list safety_timer;
>> -struct timer_list maintenance_timer;
>> +struct hrtimer safety_timer;
>> +struct hrtimer maintenance_timer;
>>  struct kobject chargalg_kobject;
>>  };
>>  
>> @@ -261,38 +270,47 @@ BLOCKING_NOTIFIER_HEAD(charger_notifier_list);
>>  
>>  /**
>>   * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
>> - * @data:   pointer to the abx500_chargalg structure
>> + * @timer:  pointer to the hrtimer structure
>>   *
>>   * This function gets called when the safety timer for the charger
>>   * expires
>>   */
>> -static void abx500_chargalg_safety_timer_expired(unsigned long data)
>> +static enum hrtimer_restart
>> +abx500_chargalg_safety_timer_expired(struct hrtimer *timer)
>>  {
>> -struct abx500_chargalg *di = (struct abx500_chargalg *) data;
>> +struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
>> +safety_timer);
> 
> Empty line here.
> 
>>  dev_err(di->dev, "Safety timer expired\n");
>>  di->events.safety_timer_expired = true;
>>  
>>  /* Trigger execution of the algorithm instantly */
>>  queue_work(di->chargalg_wq, &di->chargalg_work);
>> +
>> +return HRTIMER_NORESTART;
>>  }
>>  
>>  /**
>>   * abx500_chargalg_maintenance_timer_expired() - Expiration of
>>   * the maintenance timer
>> - * @i:  pointer to the abx500_chargalg structure
>> + * @timer:  pointer to the timer structure
>>   *
>>   * This function gets called when the maintenence timer
>>   * expires
>>   */
>> -static void abx500_chargalg_maintenance_timer_expired(unsigned long data)
>> +static enum hrtimer_restart
>> +abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer)
>> +
>>  {
>>  
>> -struct abx500_chargalg *di = (struct abx500_chargalg *) data;
>> +struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
>> +maintenance_timer);
>>  dev_dbg(di->dev, "Maintenance timer expired\n");
>>  di->events.maintenance_timer_expired = true;
>>  
>>  /* Trigger execution

[PATCH 0/6] perf: Driver specific configuration for PMU

2016-07-19 Thread Mathieu Poirier
This patchset adds the possiblity of specifying PMU driver configuration
directly from the perf command line.  Anything that falls within the
event specifiers '/.../' and that is preceeded by the '@' symbol is
treated as a configurable.  Two formats are supported, @cfg and
@cfg=config.

For example:

perf record -e some_event/@cfg1/ ...

or

perf record -e some_event/@cfg2=config/ ...

or

perf record -e some_event/@cfg1,@cfg2=config/ ...

The above are all valid configuration and will see the strings 'cfg1'
and 'cfg2=config' sent to the PMU driver for parsing and interpretation
using the existing ioctl() mechanism.

The primary customers for this feature are the CoreSight drivers where
the selection of a sink (where trace data is accumulated) needs to be
done in a previous, and separated step, from the launching of the perf
command.

As such something that used to be a two-step process:

# echo 1 > /sys/bus/coresight/devices/2007.etr/enable_sink
# perf record -e cs_etm//u --per-thread  uname

is integrated in a single command:

# perf record -e cs_etm/@sink=2007.etr/u --per-thread  uname

The patches include both the kernel and user space part so that the
solution is complete and found in a single place.

Last but not least it is based on 4.7-rc7 assumes that these
patches [1] have been applied.

Thanks,
Mathieu

[1]. https://lkml.org/lkml/2016/7/14/642

Mathieu Poirier (6):
  perf/core: Adding PMU driver specific configuration
  perf: Passing struct perf_event to function setup_aux()
  perf tools: add infrastructure for PMU specific configuration
  perf tools: pushing driver configuration down to the kernel
  coresight: adding sink parameter to function coresight_build_path()
  coresight: etm-perf: incorporating sink definition from cmd line

 arch/x86/events/intel/bts.c  |   4 +-
 arch/x86/events/intel/pt.c   |   5 +-
 drivers/hwtracing/coresight/coresight-etm-perf.c | 105 ++-
 drivers/hwtracing/coresight/coresight-priv.h |   3 +-
 drivers/hwtracing/coresight/coresight.c  |  40 ++---
 include/linux/perf_event.h   |  11 ++-
 include/uapi/linux/perf_event.h  |   1 +
 kernel/events/core.c |  16 
 kernel/events/ring_buffer.c  |   2 +-
 tools/perf/builtin-record.c  |   9 ++
 tools/perf/util/evlist.c |  24 ++
 tools/perf/util/evlist.h |   3 +
 tools/perf/util/evsel.c  |  33 +++
 tools/perf/util/evsel.h  |   7 ++
 tools/perf/util/parse-events.c   |  67 +++
 tools/perf/util/parse-events.h   |   1 +
 tools/perf/util/parse-events.l   |  12 +++
 tools/perf/util/parse-events.y   |  11 +++
 18 files changed, 314 insertions(+), 40 deletions(-)

-- 
2.7.4



[PATCH 1/6] perf/core: Adding PMU driver specific configuration

2016-07-19 Thread Mathieu Poirier
This patch somewhat mimics the work done on address filters to
add the infrastructure needed to pass PMU specific HW
configuration to the driver before a session starts.

Signed-off-by: Mathieu Poirier 
---
 include/linux/perf_event.h  |  9 +
 include/uapi/linux/perf_event.h |  1 +
 kernel/events/core.c| 16 
 3 files changed, 26 insertions(+)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 1a827cecd62f..70bfd59afa98 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -168,6 +168,9 @@ struct hw_perf_event {
/* Last sync'ed generation of filters */
unsigned long   addr_filters_gen;
 
+   /* HW specific configuration */
+   void*drv_configs;
+
 /*
  * hw_perf_event::state flags; used to track the PERF_EF_* state.
  */
@@ -442,6 +445,12 @@ struct pmu {
 * Filter events for PMU-specific reasons.
 */
int (*filter_match) (struct perf_event *event); /* optional 
*/
+
+   /*
+* PMU driver specific configuration.
+*/
+   int (*set_drv_configs)  (struct perf_event *event,
+void __user *arg); /* optional */
 };
 
 /**
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 36ce552cf6a9..1bba3580882f 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -403,6 +403,7 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_ID  _IOR('$', 7, __u64 *)
 #define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32)
 #define PERF_EVENT_IOC_PAUSE_OUTPUT_IOW('$', 9, __u32)
+#define PERF_EVENT_IOC_SET_DRV_CONFIGS _IOW('$', 10, char *)
 
 enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
diff --git a/kernel/events/core.c b/kernel/events/core.c
index eb37c41b8452..28bbd5f18f17 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4414,6 +4414,8 @@ static int perf_event_set_output(struct perf_event *event,
 struct perf_event *output_event);
 static int perf_event_set_filter(struct perf_event *event, void __user *arg);
 static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd);
+static int perf_event_set_drv_configs(struct perf_event *event,
+ void __user *arg);
 
 static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned 
long arg)
 {
@@ -4483,6 +4485,10 @@ static long _perf_ioctl(struct perf_event *event, 
unsigned int cmd, unsigned lon
rcu_read_unlock();
return 0;
}
+
+   case PERF_EVENT_IOC_SET_DRV_CONFIGS:
+   return perf_event_set_drv_configs(event, (void __user *)arg);
+
default:
return -ENOTTY;
}
@@ -4515,6 +4521,7 @@ static long perf_compat_ioctl(struct file *file, unsigned 
int cmd,
switch (_IOC_NR(cmd)) {
case _IOC_NR(PERF_EVENT_IOC_SET_FILTER):
case _IOC_NR(PERF_EVENT_IOC_ID):
+   case _IOC_NR(PERF_EVENT_IOC_SET_DRV_CONFIGS):
/* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */
if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
cmd &= ~IOCSIZE_MASK;
@@ -7585,6 +7592,15 @@ void perf_bp_event(struct perf_event *bp, void *data)
 }
 #endif
 
+static int perf_event_set_drv_configs(struct perf_event *event,
+ void __user *arg)
+{
+   if (!event->pmu->set_drv_configs)
+   return -EINVAL;
+
+   return event->pmu->set_drv_configs(event, arg);
+}
+
 /*
  * Allocate a new address filter
  */
-- 
2.7.4



[PATCH 5/6] coresight: adding sink parameter to function coresight_build_path()

2016-07-19 Thread Mathieu Poirier
Up to now function coresight_build_path() was counting on a sink to
have been selected (from sysFS) prior to being called.  This patch
adds a string argument so that a sink matching the argument can be
selected.

Signed-off-by: Mathieu Poirier 
---
 drivers/hwtracing/coresight/coresight-etm-perf.c |  2 +-
 drivers/hwtracing/coresight/coresight-priv.h |  3 +-
 drivers/hwtracing/coresight/coresight.c  | 40 +++-
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c 
b/drivers/hwtracing/coresight/coresight-etm-perf.c
index f4174f36c5a0..f8c7a8733b23 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -184,7 +184,7 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
 * list of devices from source to sink that can be
 * referenced later when the path is actually needed.
 */
-   event_data->path[cpu] = coresight_build_path(csdev);
+   event_data->path[cpu] = coresight_build_path(csdev, NULL);
if (!event_data->path[cpu])
goto err;
}
diff --git a/drivers/hwtracing/coresight/coresight-priv.h 
b/drivers/hwtracing/coresight/coresight-priv.h
index decfd52b5dc3..31d248819377 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -98,7 +98,8 @@ static inline void CS_UNLOCK(void __iomem *addr)
 void coresight_disable_path(struct list_head *path);
 int coresight_enable_path(struct list_head *path, u32 mode);
 struct coresight_device *coresight_get_sink(struct list_head *path);
-struct list_head *coresight_build_path(struct coresight_device *csdev);
+struct list_head *coresight_build_path(struct coresight_device *csdev,
+  const char *sink);
 void coresight_release_path(struct list_head *path);
 
 #ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
diff --git a/drivers/hwtracing/coresight/coresight.c 
b/drivers/hwtracing/coresight/coresight.c
index bb20ee9747e1..f4b960f48ca4 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -372,30 +372,41 @@ struct coresight_device *coresight_get_sink(struct 
list_head *path)
  * _coresight_build_path - recursively build a path from a @csdev to a sink.
  * @csdev: The device to start from.
  * @path:  The list to add devices to.
+ * @sink:  The name of the sink this path should connect with.
  *
- * The tree of Coresight device is traversed until an activated sink is
- * found.  From there the sink is added to the list along with all the
- * devices that led to that point - the end result is a list from source
- * to sink. In that list the source is the first device and the sink the
- * last one.
+ * The tree of Coresight device is traversed until an activated sink or
+ * the one specified by @sink is found.
+ * From there the sink is added to the list along with all the devices that
+ * led to that point - the end result is a list from source to sink. In that
+ * list the source is the first device and the sink the last one.
  */
 static int _coresight_build_path(struct coresight_device *csdev,
-struct list_head *path)
+struct list_head *path, const char *sink)
 {
int i;
bool found = false;
struct coresight_node *node;
 
-   /* An activated sink has been found.  Enqueue the element */
-   if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
-csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && csdev->activated)
-   goto out;
+   /*
+* First see if we are dealing with a sink.  If we have one check if
+* it was selected via sysFS or the perf cmd line.
+*/
+   if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+   csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) {
+   /* Activated via perf cmd line */
+   if (sink && !strcmp(dev_name(&csdev->dev), sink))
+   goto out;
+   /* Activated via sysFS */
+   if (csdev->activated)
+   goto out;
+   }
 
/* Not a sink - recursively explore each port found on this element */
for (i = 0; i < csdev->nr_outport; i++) {
struct coresight_device *child_dev = csdev->conns[i].child_dev;
 
-   if (child_dev && _coresight_build_path(child_dev, path) == 0) {
+   if (child_dev &&
+   _coresight_build_path(child_dev, path, sink) == 0) {
found = true;
break;
}
@@ -422,7 +433,8 @@ out:
return 0;
 }
 
-struct list_head *coresight_build_path(struct coresight_device *cs

[PATCH 6/6] coresight: etm-perf: incorporating sink definition from cmd line

2016-07-19 Thread Mathieu Poirier
Now that PMU specific configuration is available as part of the event,
lookup the sink identified by users from the perf command line and build
a path from source to sink.

With this functionality it is no longer required to select a sink in a
separate step (from sysFS) before a perf trace session can be started.

Signed-off-by: Mathieu Poirier 
---
 drivers/hwtracing/coresight/coresight-etm-perf.c | 101 ++-
 1 file changed, 100 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c 
b/drivers/hwtracing/coresight/coresight-etm-perf.c
index f8c7a8733b23..5658a7411a66 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -71,11 +72,20 @@ static const struct attribute_group *etm_pmu_attr_groups[] 
= {
 
 static void etm_event_read(struct perf_event *event) {}
 
+static void etm_event_destroy(struct perf_event *event)
+{
+   kfree(event->hw.drv_configs);
+   event->hw.drv_configs = NULL;
+}
+
 static int etm_event_init(struct perf_event *event)
 {
if (event->attr.type != etm_pmu.type)
return -ENOENT;
 
+   event->destroy = etm_event_destroy;
+   event->hw.drv_configs = NULL;
+
return 0;
 }
 
@@ -159,6 +169,7 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
   int nr_pages, bool overwrite)
 {
int cpu;
+   char *cmdl_sink;
cpumask_t *mask;
struct coresight_device *sink;
struct etm_event_data *event_data = NULL;
@@ -171,6 +182,12 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
 
mask = &event_data->mask;
 
+   /*
+* If a sink was specified from the perf cmdline it will be part of
+* the event's drv_configs.
+*/
+   cmdl_sink = (char *)event->hw.drv_configs;
+
/* Setup the path for each CPU in a trace session */
for_each_cpu(cpu, mask) {
struct coresight_device *csdev;
@@ -184,7 +201,7 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
 * list of devices from source to sink that can be
 * referenced later when the path is actually needed.
 */
-   event_data->path[cpu] = coresight_build_path(csdev, NULL);
+   event_data->path[cpu] = coresight_build_path(csdev, cmdl_sink);
if (!event_data->path[cpu])
goto err;
}
@@ -342,6 +359,87 @@ static void etm_event_del(struct perf_event *event, int 
mode)
etm_event_stop(event, PERF_EF_UPDATE);
 }
 
+enum {
+   ETM_TOKEN_SINK_CPU,
+   ETM_TOKEN_SINK,
+   ETM_TOKEN_ERR,
+};
+
+static const match_table_t drv_cfg_tokens = {
+   {ETM_TOKEN_SINK_CPU, "sink=cpu%d:%s"},
+   {ETM_TOKEN_SINK, "sink=%s"},
+   {ETM_TOKEN_ERR, NULL},
+};
+
+static int etm_set_drv_configs(struct perf_event *event, void __user *arg)
+{
+   char *config, *sink = NULL;
+   int cpu = -1, token, ret = 0;
+   substring_t args[MAX_OPT_ARGS];
+
+   /* Only one sink per event */
+   if (event->hw.drv_configs != NULL) {
+   ret = -EINVAL;
+   goto err;
+   }
+
+   /* Make user supplied input usable */
+   config = strndup_user(arg, PAGE_SIZE);
+   if (IS_ERR(config)) {
+   ret = PTR_ERR(config);
+   goto err;
+   }
+
+   /* See above declared @drv_cfg_tokens for the usable formats */
+   token = match_token(config, drv_cfg_tokens, args);
+   switch (token) {
+   case ETM_TOKEN_SINK:
+   /* Just a sink has been specified */
+   sink = match_strdup(&args[0]);
+   if (IS_ERR(sink)) {
+   ret = PTR_ERR(sink);
+   goto err;
+   }
+   break;
+   case ETM_TOKEN_SINK_CPU:
+   /* We have a sink and a CPU */
+
+   /* First get the cpu */
+   if (match_int(&args[0], &cpu)) {
+   ret = -EINVAL;
+   goto err;
+   }
+
+   /* Then the sink */
+   sink = match_strdup(&args[1]);
+   if (IS_ERR(sink)) {
+   ret = PTR_ERR(sink);
+   goto err;
+   }
+   break;
+   default:
+   ret = -EINVAL;
+   goto err;
+   }
+
+   /*
+* If the CPUs don't match the sink is destined to another path.  This
+* isn't as an error hence not setting @ret.
+*/
+   if (event->cpu != cpu)
+   goto err;
+
+   /* We have a valid configuration */
+   event->hw.drv_configs = sink;
+
+out:
+ 

[PATCH 4/6] perf tools: pushing driver configuration down to the kernel

2016-07-19 Thread Mathieu Poirier
Now that PMU specific driver configuration are queued in
evsel::drv_config_terms, all we need to do is re-use the current
ioctl() mechanism to push down the information to the kernel
driver.

Signed-off-by: Mathieu Poirier 
---
 tools/perf/builtin-record.c |  9 +
 tools/perf/util/evlist.c| 24 
 tools/perf/util/evlist.h|  3 +++
 tools/perf/util/evsel.c | 32 
 tools/perf/util/evsel.h |  3 +++
 5 files changed, 71 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index dc3fcb597e4c..5d2e45e189f0 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -348,6 +348,7 @@ static int record__open(struct record *rec)
struct perf_evlist *evlist = rec->evlist;
struct perf_session *session = rec->session;
struct record_opts *opts = &rec->opts;
+   struct perf_evsel_config_term *err_term;
int rc = 0;
 
perf_evlist__config(evlist, opts, &callchain_param);
@@ -377,6 +378,14 @@ try_again:
goto out;
}
 
+   if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) {
+   error("failed to set config \"%s\" on event %s with %d (%s)\n",
+   err_term->val.drv_cfg, perf_evsel__name(pos), errno,
+   strerror_r(errno, msg, sizeof(msg)));
+   rc = -1;
+   goto out;
+   }
+
if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
 opts->auxtrace_mmap_pages,
 opts->auxtrace_snapshot_mode) < 0) {
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index e82ba90cc969..084086fc0d6f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1345,6 +1345,30 @@ int perf_evlist__apply_filters(struct perf_evlist 
*evlist, struct perf_evsel **e
return err;
 }
 
+int perf_evlist__apply_drv_configs(struct perf_evlist *evlist,
+  struct perf_evsel **err_evsel,
+  struct perf_evsel_config_term **err_term)
+{
+   struct perf_evsel *evsel;
+   int err = 0;
+   const int ncpus = cpu_map__nr(evlist->cpus),
+ nthreads = thread_map__nr(evlist->threads);
+
+   evlist__for_each(evlist, evsel) {
+   if (list_empty(&evsel->drv_config_terms))
+   continue;
+
+   err = perf_evsel__apply_drv_configs(evsel, ncpus,
+   nthreads, err_term);
+   if (err) {
+   *err_evsel = evsel;
+   break;
+   }
+   }
+
+   return err;
+}
+
 int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
 {
struct perf_evsel *evsel;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index d740fb877ab6..b64c501298d9 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -189,6 +189,9 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, 
struct cpu_map *cpus,
   struct thread_map *threads);
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target 
*target);
 int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel 
**err_evsel);
+int perf_evlist__apply_drv_configs(struct perf_evlist *evlist,
+  struct perf_evsel **err_evsel,
+  struct perf_evsel_config_term **term);
 
 void __perf_evlist__set_leader(struct list_head *list);
 void perf_evlist__set_leader(struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 7f97bae594ff..447c5525e411 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1002,6 +1002,27 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
return -1;
 }
 
+int perf_evsel__apply_drv_configs(struct perf_evsel *evsel,
+ int ncpus, int nthreads,
+ struct perf_evsel_config_term **err_term)
+{
+   int err = 0;
+   struct perf_evsel_config_term *term;
+
+   list_for_each_entry(term, &evsel->drv_config_terms, list) {
+   err = perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+   PERF_EVENT_IOC_SET_DRV_CONFIGS,
+   (void *)term->val.drv_cfg);
+
+   if (err) {
+   *err_term = term;
+   break;
+   }
+   }
+
+   return err;
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel)
 {
int nthreads = thread_map__nr(evsel->threads);
@@ -1067,6 +1088,16 @@ static void perf_evsel__free_config_terms(struct 
perf_evsel *evsel)
}
 }
 
+sta

[PATCH 3/6] perf tools: add infrastructure for PMU specific configuration

2016-07-19 Thread Mathieu Poirier
This patchset adds PMU driver specific configuration to the parser
infrastructure by preceding any term with the '@' letter.  As such
doing something like:

perf record -e some_event/@cfg1,@cfg2=config/ ...

will see 'cfg1' and 'cfg2=config' being added to the list of evsel config
terms.  Token 'cfg1' and 'cfg2=config' are not processed in user space
and are meant to be interpreted by the PMU driver.

First the lexer/parser are supplemented with the required definitions to
recognise the driver specific configuration.  From there they are simply
added to the list of event terms.  The bulk of the work is done in
function "parse_events_add_pmu()" where driver config event terms are
added to a new list of driver config terms, which in turn spliced with
the event's new driver configuration list.

Signed-off-by: Mathieu Poirier 
---
 tools/perf/util/evsel.c|  1 +
 tools/perf/util/evsel.h|  4 +++
 tools/perf/util/parse-events.c | 67 +++---
 tools/perf/util/parse-events.h |  1 +
 tools/perf/util/parse-events.l | 12 
 tools/perf/util/parse-events.y | 11 +++
 6 files changed, 79 insertions(+), 17 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5d7037ef7d3b..7f97bae594ff 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -213,6 +213,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel->bpf_fd  = -1;
INIT_LIST_HEAD(&evsel->node);
INIT_LIST_HEAD(&evsel->config_terms);
+   INIT_LIST_HEAD(&evsel->drv_config_terms);
perf_evsel__object.init(evsel);
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
perf_evsel__calc_id_pos(evsel);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index c1f10159804c..0441be00a366 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -44,6 +44,7 @@ enum {
PERF_EVSEL__CONFIG_TERM_CALLGRAPH,
PERF_EVSEL__CONFIG_TERM_STACK_USER,
PERF_EVSEL__CONFIG_TERM_INHERIT,
+   PERF_EVSEL__CONFIG_TERM_DRV_CFG,
PERF_EVSEL__CONFIG_TERM_MAX,
 };
 
@@ -55,6 +56,7 @@ struct perf_evsel_config_term {
u64 freq;
booltime;
char*callgraph;
+   char*drv_cfg;
u64 stack_user;
boolinherit;
} val;
@@ -75,6 +77,7 @@ struct perf_evsel_config_term {
  *  PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
  *  is used there is an id sample appended to non-sample events
  * @priv:   And what is in its containing unnamed union are tool specific
+ * @drv_config_terms: List of configurables sent directly to the PMU driver
  */
 struct perf_evsel {
struct list_headnode;
@@ -122,6 +125,7 @@ struct perf_evsel {
char*group_name;
boolcmdline_group_boundary;
struct list_headconfig_terms;
+   struct list_headdrv_config_terms;
int bpf_fd;
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c6fd0479f4cd..a12284091666 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -302,7 +302,8 @@ static struct perf_evsel *
 __add_event(struct list_head *list, int *idx,
struct perf_event_attr *attr,
char *name, struct cpu_map *cpus,
-   struct list_head *config_terms)
+   struct list_head *config_terms,
+   struct list_head *drv_config_terms)
 {
struct perf_evsel *evsel;
 
@@ -321,6 +322,10 @@ __add_event(struct list_head *list, int *idx,
if (config_terms)
list_splice(config_terms, &evsel->config_terms);
 
+   if (drv_config_terms)
+   list_splice(drv_config_terms, &evsel->drv_config_terms);
+
+
list_add_tail(&evsel->node, list);
return evsel;
 }
@@ -329,7 +334,8 @@ static int add_event(struct list_head *list, int *idx,
 struct perf_event_attr *attr, char *name,
 struct list_head *config_terms)
 {
-   return __add_event(list, idx, attr, name, NULL, config_terms) ? 0 : 
-ENOMEM;
+   return __add_event(list, idx, attr, name,
+  NULL, config_terms, NULL) ? 0 : -ENOMEM;
 }
 
 static int parse_aliases(char *str, const char 
*names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -900,6 +906,7 @@ static const char 
*config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
[PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size",
[PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit",
[PARSE_EVENTS__TERM_TYPE_INHERIT]   = "inherit",
+   [PARSE_EVENTS__TERM_TYPE_DRV_CFG]  

[PATCH 2/6] perf: Passing struct perf_event to function setup_aux()

2016-07-19 Thread Mathieu Poirier
Some information, like driver specific configuration, is found
in the hw_perf_event  structure.  As such pass a 'struct perf_event'
to function setup_aux() rather than just the CPU number so that
individual drivers can make the right configuration when setting
up a session.

Signed-off-by: Mathieu Poirier 
Cc: Alexander Shishkin 
---
 arch/x86/events/intel/bts.c  | 4 +++-
 arch/x86/events/intel/pt.c   | 5 +++--
 drivers/hwtracing/coresight/coresight-etm-perf.c | 4 ++--
 include/linux/perf_event.h   | 2 +-
 kernel/events/ring_buffer.c  | 2 +-
 5 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index 0a6e393a2e62..98155c2dfcce 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -68,8 +68,10 @@ static size_t buf_size(struct page *page)
 }
 
 static void *
-bts_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool overwrite)
+bts_buffer_setup_aux(struct perf_event *event, void **pages,
+int nr_pages, bool overwrite)
 {
+   int cpu = event->cpu;
struct bts_buffer *buf;
struct page *page;
int node = (cpu == -1) ? cpu : cpu_to_node(cpu);
diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c
index 04bb5fb5a8d7..5178c5de0b19 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -1003,10 +1003,11 @@ static int pt_buffer_init_topa(struct pt_buffer *buf, 
unsigned long nr_pages,
  * Return: Our private PT buffer structure.
  */
 static void *
-pt_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool snapshot)
+pt_buffer_setup_aux(struct perf_event *event, void **pages,
+   int nr_pages, bool snapshot)
 {
struct pt_buffer *buf;
-   int node, ret;
+   int node, ret, cpu = event->cpu;
 
if (!nr_pages)
return NULL;
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c 
b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 755125f7917f..f4174f36c5a0 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -155,7 +155,7 @@ static void etm_free_aux(void *data)
schedule_work(&event_data->work);
 }
 
-static void *etm_setup_aux(int event_cpu, void **pages,
+static void *etm_setup_aux(struct perf_event *event, void **pages,
   int nr_pages, bool overwrite)
 {
int cpu;
@@ -163,7 +163,7 @@ static void *etm_setup_aux(int event_cpu, void **pages,
struct coresight_device *sink;
struct etm_event_data *event_data = NULL;
 
-   event_data = alloc_event_data(event_cpu);
+   event_data = alloc_event_data(event->cpu);
if (!event_data)
return NULL;
 
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 70bfd59afa98..de23a1b82f30 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -407,7 +407,7 @@ struct pmu {
/*
 * Set up pmu-private data structures for an AUX area
 */
-   void *(*setup_aux)  (int cpu, void **pages,
+   void *(*setup_aux)  (struct perf_event *event, void **pages,
 int nr_pages, bool overwrite);
/* optional */
 
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index ae9b90dc9a5a..56aba90af437 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -616,7 +616,7 @@ int rb_alloc_aux(struct ring_buffer *rb, struct perf_event 
*event,
goto out;
}
 
-   rb->aux_priv = event->pmu->setup_aux(event->cpu, rb->aux_pages, 
nr_pages,
+   rb->aux_priv = event->pmu->setup_aux(event, rb->aux_pages, nr_pages,
 overwrite);
if (!rb->aux_priv)
goto out;
-- 
2.7.4



[PATCH V3 3/3] perf tools: adding coresight etm PMU record capabilities

2016-07-20 Thread Mathieu Poirier
Coresight ETMs are IP blocks used to perform HW assisted tracing
on a CPU core.  This patch introduce the required auxiliary API
functions allowing the perf core to interact with a tracer.

Signed-off-by: Mathieu Poirier 
Acked-by: Adrian Hunter 
---
 MAINTAINERS |   4 +
 tools/perf/arch/arm/util/Build  |   2 +-
 tools/perf/arch/arm/util/auxtrace.c |  54 
 tools/perf/arch/arm/util/cs-etm.c   | 559 
 tools/perf/arch/arm/util/cs-etm.h   |  23 ++
 tools/perf/arch/arm64/util/Build|   4 +
 tools/perf/util/auxtrace.c  |   1 +
 tools/perf/util/auxtrace.h  |   1 +
 tools/perf/util/cs-etm.h|  74 +
 9 files changed, 721 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/arch/arm/util/auxtrace.c
 create mode 100644 tools/perf/arch/arm/util/cs-etm.c
 create mode 100644 tools/perf/arch/arm/util/cs-etm.h
 create mode 100644 tools/perf/util/cs-etm.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a025ab95c92e..ed3d9a350bac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1090,6 +1090,10 @@ F:   Documentation/trace/coresight.txt
 F: Documentation/devicetree/bindings/arm/coresight.txt
 F: Documentation/ABI/testing/sysfs-bus-coresight-devices-*
 F: tools/perf/arch/arm/util/pmu.c
+F: tools/perf/arch/arm/util/auxtrace.c
+F: tools/perf/arch/arm/util/cs-etm.c
+F: tools/perf/arch/arm/util/cs-etm.h
+F: tools/perf/util/cs-etm.h
 
 ARM/CORGI MACHINE SUPPORT
 M: Richard Purdie 
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index 4093fd146f46..e64c5f216448 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -3,4 +3,4 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o
 libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 
-libperf-$(CONFIG_AUXTRACE) += pmu.o
+libperf-$(CONFIG_AUXTRACE) += pmu.o auxtrace.o cs-etm.o
diff --git a/tools/perf/arch/arm/util/auxtrace.c 
b/tools/perf/arch/arm/util/auxtrace.c
new file mode 100644
index ..8edf2cb71564
--- /dev/null
+++ b/tools/perf/arch/arm/util/auxtrace.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier 
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+
+#include "../../util/auxtrace.h"
+#include "../../util/evlist.h"
+#include "../../util/pmu.h"
+#include "cs-etm.h"
+
+struct auxtrace_record
+*auxtrace_record__init(struct perf_evlist *evlist, int *err)
+{
+   struct perf_pmu *cs_etm_pmu;
+   struct perf_evsel *evsel;
+   bool found_etm = false;
+
+   cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
+
+   if (evlist) {
+   evlist__for_each_entry(evlist, evsel) {
+   if (cs_etm_pmu &&
+   evsel->attr.type == cs_etm_pmu->type)
+   found_etm = true;
+   }
+   }
+
+   if (found_etm)
+   return cs_etm_record_init(err);
+
+   /*
+* Clear 'err' even if we haven't found a cs_etm event - that way perf
+* record can still be used even if tracers aren't present.  The NULL
+* return value will take care of telling the infrastructure HW tracing
+* isn't available.
+*/
+   *err = 0;
+   return NULL;
+}
diff --git a/tools/perf/arch/arm/util/cs-etm.c 
b/tools/perf/arch/arm/util/cs-etm.c
new file mode 100644
index ..829c479614f1
--- /dev/null
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier 
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+#include 
+#include 

[PATCH V3 1/3] tools: Copy the header file needed by perf tools

2016-07-20 Thread Mathieu Poirier
Directly accessing kernel files is not allowed anymore.  As such
making file coresight-pmu.h accessible by the perf tools and complain
if this copy strays from the one found in the main kernel tree.

Signed-off-by: Mathieu Poirier 
---
 tools/perf/MANIFEST  | 1 +
 tools/perf/Makefile.perf | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index ad2534df4ba6..f181c613d9aa 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -77,4 +77,5 @@ tools/include/linux/stringify.h
 tools/include/linux/types.h
 tools/include/linux/err.h
 tools/include/linux/bitmap.h
+tools/include/linux/coresight-pmu.h
 tools/arch/*/include/uapi/asm/perf_regs.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 6641abb97f0a..9ad53b9868d8 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -429,6 +429,9 @@ $(PERF_IN): prepare FORCE
@(test -f ../../include/asm-generic/bitops/fls64.h && ( \
 (diff -B ../include/asm-generic/bitops/fls64.h 
../../include/asm-generic/bitops/fls64.h >/dev/null) \
 || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs 
from kernel" >&2 )) || true
+   @(test -f ../../include/linux/coresight-pmu.h && ( \
+   (diff -B ../include/linux/coresight-pmu.h 
../../include/linux/coresight-pmu.h >/dev/null) \
+   || echo "Warning: tools/include/linux/coresight-pmu.h differs from 
kernel" >&2 )) || true
$(Q)$(MAKE) $(build)=perf
 
 $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
-- 
2.7.4



[PATCH V3 0/3] perf tools: coresight PMU recording capabilities

2016-07-20 Thread Mathieu Poirier
This is the third revision of this set and has been rebased to [1].

It is aimed at supporting trace acquisition and decoding using the ARM
CoreSight drivers. The library is now out and accessible by anyone[2],
branch "opencsd-0v002" is stable and the one we advise to use.

Part of that branch is a "HOWTO.md" that describes how to perform on-target
trace acquisition, along with how to setup the library and perf tools for
off system trace decoding.

Here are a couple of pastebins demonstrating the solution: 

$ perf report --stdio -D [3]
$ perf report --stdio [4]

And a snippet of the output from the "cs-etm-disasem.py" script that
will be upstreamed in an upcoming patchset. 

FILE: /lib/aarch64-linux-gnu/ld-2.21.so CPU: 3
  7fab57fd80:   910003e0mov x0, sp
  7fab57fd84:   94000d53bl  7fab5832d0 
FILE: /lib/aarch64-linux-gnu/ld-2.21.so CPU: 3
  7fab5832d0:   d11203ffsub sp, sp, #0x480
FILE: /lib/aarch64-linux-gnu/ld-2.21.so CPU: 3
  7fab5832d4:   a9ba7bfdstp x29, x30, [sp,#-96]!
  7fab5832d8:   910003fdmov x29, sp
  7fab5832dc:   a90363f7stp x23, x24, [sp,#48]
  7fab5832e0:   9101e3b7add x23, x29, #0x78
  7fab5832e4:   a90573fbstp x27, x28, [sp,#80]
  7fab5832e8:   a90153f3stp x19, x20, [sp,#16]
  7fab5832ec:   aa0003fbmov x27, x0
  7fab5832f0:   910a82e1add x1, x23, #0x2a0
  7fab5832f4:   a9025bf5stp x21, x22, [sp,#32]
  7fab5832f8:   a9046bf9stp x25, x26, [sp,#64]
  7fab5832fc:   910102e0add x0, x23, #0x40
  7fab583300:   f800841fstr xzr, [x0],#8
  7fab583304:   eb01001fcmp x0, x1
  7fab583308:   54c1b.ne7fab583300 
FILE: /lib/aarch64-linux-gnu/ld-2.21.so CPU: 3
  7fab583300:   f800841fstr xzr, [x0],#8
  7fab583304:   eb01001fcmp x0, x1
  7fab583308:   54c1b.ne7fab583300 
FILE: /lib/aarch64-linux-gnu/ld-2.21.so CPU: 3
  7fab583300:   f800841fstr xzr, [x0],#8
  7fab583304:   eb01001fcmp x0, x1
  7fab583308:   54c1b.ne7fab583300 
...
...

Regards,
Mathieu

[1]. git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git perf/core
[2]. https://github.com/Linaro/OpenCSD/
[3]. http://pastebin.com/u9tgdwjF
[4]. http://pastebin.com/V9N3bnEq

Changes for V3:
- Rebased to [1]. 

Changes for V2:
- Rebased on perf tree tip.
- Fixed file list in MAINTAINERS's file.
- Added Adrian Hunter's Acked-by.
- Reworked ifndef/endif in config/Makefile to avoid duplication.
- Patch 1/3, mandatory to make things compile.

Mathieu Poirier (3):
  tools: Copy the header file needed by perf tools
  perf tools: making coresight PMU listable
  perf tools: adding coresight etm PMU record capabilities

 MAINTAINERS |   5 +
 tools/perf/MANIFEST |   1 +
 tools/perf/Makefile.perf|   3 +
 tools/perf/arch/arm/util/Build  |   2 +
 tools/perf/arch/arm/util/auxtrace.c |  54 
 tools/perf/arch/arm/util/cs-etm.c   | 559 
 tools/perf/arch/arm/util/cs-etm.h   |  23 ++
 tools/perf/arch/arm/util/pmu.c  |  34 +++
 tools/perf/arch/arm64/util/Build|   4 +
 tools/perf/config/Makefile  |  11 +-
 tools/perf/util/auxtrace.c  |   1 +
 tools/perf/util/auxtrace.h  |   1 +
 tools/perf/util/cs-etm.h|  74 +
 13 files changed, 768 insertions(+), 4 deletions(-)
 create mode 100644 tools/perf/arch/arm/util/auxtrace.c
 create mode 100644 tools/perf/arch/arm/util/cs-etm.c
 create mode 100644 tools/perf/arch/arm/util/cs-etm.h
 create mode 100644 tools/perf/arch/arm/util/pmu.c
 create mode 100644 tools/perf/util/cs-etm.h

-- 
2.7.4



[PATCH V3 2/3] perf tools: making coresight PMU listable

2016-07-20 Thread Mathieu Poirier
Adding the required mechanic allowing 'perf list pmu' to
discover coresight ETM/PTM tracers.

Signed-off-by: Mathieu Poirier 
Acked-by: Adrian Hunter 
---
 MAINTAINERS|  1 +
 tools/perf/arch/arm/util/Build |  2 ++
 tools/perf/arch/arm/util/pmu.c | 34 ++
 tools/perf/config/Makefile | 11 +++
 4 files changed, 44 insertions(+), 4 deletions(-)
 create mode 100644 tools/perf/arch/arm/util/pmu.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 1209323b7e43..a025ab95c92e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1089,6 +1089,7 @@ F:drivers/hwtracing/coresight/*
 F: Documentation/trace/coresight.txt
 F: Documentation/devicetree/bindings/arm/coresight.txt
 F: Documentation/ABI/testing/sysfs-bus-coresight-devices-*
+F: tools/perf/arch/arm/util/pmu.c
 
 ARM/CORGI MACHINE SUPPORT
 M: Richard Purdie 
diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build
index f98da17357c0..4093fd146f46 100644
--- a/tools/perf/arch/arm/util/Build
+++ b/tools/perf/arch/arm/util/Build
@@ -2,3 +2,5 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o
 
 libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
+
+libperf-$(CONFIG_AUXTRACE) += pmu.o
diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c
new file mode 100644
index ..af9fb666b44f
--- /dev/null
+++ b/tools/perf/arch/arm/util/pmu.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright(C) 2015 Linaro Limited. All rights reserved.
+ * Author: Mathieu Poirier 
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+#include 
+
+#include "../../util/pmu.h"
+
+struct perf_event_attr
+*perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
+{
+#ifdef HAVE_AUXTRACE_SUPPORT
+   if (!strcmp(pmu->name, CORESIGHT_ETM_PMU_NAME)) {
+   /* add ETM default config here */
+   pmu->selectable = true;
+   }
+#endif
+   return NULL;
+}
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 24803c58049a..72edf83d76b7 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -746,10 +746,13 @@ ifdef LIBBABELTRACE
 endif
 
 ifndef NO_AUXTRACE
-  ifeq ($(feature-get_cpuid), 0)
-msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables 
support for auxtrace/Intel PT, please install a newer gcc);
-NO_AUXTRACE := 1
-  else
+  ifeq ($(ARCH),x86)
+ifeq ($(feature-get_cpuid), 0)
+  msg := $(warning Your gcc lacks the __get_cpuid() builtin, disables 
support for auxtrace/Intel PT, please install a newer gcc);
+  NO_AUXTRACE := 1
+endif
+  endif
+  ifndef NO_AUXTRACE
 $(call detected,CONFIG_AUXTRACE)
 CFLAGS += -DHAVE_AUXTRACE_SUPPORT
   endif
-- 
2.7.4



[PATCH V2 1/6] perf/core: Adding PMU driver specific configuration

2016-07-20 Thread Mathieu Poirier
This patch somewhat mimics the work done on address filters to
add the infrastructure needed to pass PMU specific HW
configuration to the driver before a session starts.

Signed-off-by: Mathieu Poirier 
---
 include/linux/perf_event.h|  9 +
 include/uapi/linux/perf_event.h   |  1 +
 kernel/events/core.c  | 16 
 tools/include/uapi/linux/perf_event.h |  1 +
 4 files changed, 27 insertions(+)

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 7921f4f20a58..59d61a12cf9d 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -168,6 +168,9 @@ struct hw_perf_event {
/* Last sync'ed generation of filters */
unsigned long   addr_filters_gen;
 
+   /* HW specific configuration */
+   void*drv_configs;
+
 /*
  * hw_perf_event::state flags; used to track the PERF_EF_* state.
  */
@@ -442,6 +445,12 @@ struct pmu {
 * Filter events for PMU-specific reasons.
 */
int (*filter_match) (struct perf_event *event); /* optional 
*/
+
+   /*
+* PMU driver specific configuration.
+*/
+   int (*set_drv_configs)  (struct perf_event *event,
+void __user *arg); /* optional */
 };
 
 /**
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index c66a485a24ac..90fbc5fd3925 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -407,6 +407,7 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_ID  _IOR('$', 7, __u64 *)
 #define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32)
 #define PERF_EVENT_IOC_PAUSE_OUTPUT_IOW('$', 9, __u32)
+#define PERF_EVENT_IOC_SET_DRV_CONFIGS _IOW('$', 10, char *)
 
 enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 79dae188a987..9208e6ec036f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4457,6 +4457,8 @@ static int perf_event_set_output(struct perf_event *event,
 struct perf_event *output_event);
 static int perf_event_set_filter(struct perf_event *event, void __user *arg);
 static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd);
+static int perf_event_set_drv_configs(struct perf_event *event,
+ void __user *arg);
 
 static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned 
long arg)
 {
@@ -4526,6 +4528,10 @@ static long _perf_ioctl(struct perf_event *event, 
unsigned int cmd, unsigned lon
rcu_read_unlock();
return 0;
}
+
+   case PERF_EVENT_IOC_SET_DRV_CONFIGS:
+   return perf_event_set_drv_configs(event, (void __user *)arg);
+
default:
return -ENOTTY;
}
@@ -4558,6 +4564,7 @@ static long perf_compat_ioctl(struct file *file, unsigned 
int cmd,
switch (_IOC_NR(cmd)) {
case _IOC_NR(PERF_EVENT_IOC_SET_FILTER):
case _IOC_NR(PERF_EVENT_IOC_ID):
+   case _IOC_NR(PERF_EVENT_IOC_SET_DRV_CONFIGS):
/* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */
if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
cmd &= ~IOCSIZE_MASK;
@@ -7633,6 +7640,15 @@ void perf_bp_event(struct perf_event *bp, void *data)
 }
 #endif
 
+static int perf_event_set_drv_configs(struct perf_event *event,
+ void __user *arg)
+{
+   if (!event->pmu->set_drv_configs)
+   return -EINVAL;
+
+   return event->pmu->set_drv_configs(event, arg);
+}
+
 /*
  * Allocate a new address filter
  */
diff --git a/tools/include/uapi/linux/perf_event.h 
b/tools/include/uapi/linux/perf_event.h
index c66a485a24ac..90fbc5fd3925 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -407,6 +407,7 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_ID  _IOR('$', 7, __u64 *)
 #define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32)
 #define PERF_EVENT_IOC_PAUSE_OUTPUT_IOW('$', 9, __u32)
+#define PERF_EVENT_IOC_SET_DRV_CONFIGS _IOW('$', 10, char *)
 
 enum perf_event_ioc_flags {
PERF_IOC_FLAG_GROUP = 1U << 0,
-- 
2.7.4



[PATCH V2 0/6] perf: Driver specific configuration for PMU

2016-07-20 Thread Mathieu Poirier
This patchset adds the possiblity of specifying PMU driver configuration
directly from the perf command line.  Anything that falls within the
event specifiers '/.../' and that is preceeded by the '@' symbol is
treated as a configurable.  Two formats are supported, @cfg and
@cfg=config.

For example:

perf record -e some_event/@cfg1/ ...

or

perf record -e some_event/@cfg2=config/ ...

or

perf record -e some_event/@cfg1,@cfg2=config/ ...

The above are all valid configuration and will see the strings 'cfg1'
and 'cfg2=config' sent to the PMU driver for parsing and interpretation
using the existing ioctl() mechanism.

The primary customers for this feature are the CoreSight drivers where
the selection of a sink (where trace data is accumulated) needs to be
done in a previous, and separated step, from the launching of the perf
command.

As such something that used to be a two-step process:

# echo 1 > /sys/bus/coresight/devices/2007.etr/enable_sink
# perf record -e cs_etm//u --per-thread  uname

is integrated in a single command:

# perf record -e cs_etm/@sink=2007.etr/u --per-thread  uname

The patches include both the kernel and user space part so that the
solution is complete and found in a single place.

It is based on [1] and assumes this set [2] has been applied.

Thanks,
Mathieu

Changes for V2:
- Rebased to [1] as per Jiri's request.

[1]. git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git perf/core
[2]. https://lkml.org/lkml/2016/7/20/519

Mathieu Poirier (6):
  perf/core: Adding PMU driver specific configuration
  perf: Passing struct perf_event to function setup_aux()
  perf tools: add infrastructure for PMU specific configuration
  perf tools: pushing driver configuration down to the kernel
  coresight: adding sink parameter to function coresight_build_path()
  coresight: etm-perf: incorporating sink definition from cmd line

 arch/x86/events/intel/bts.c  |   4 +-
 arch/x86/events/intel/pt.c   |   5 +-
 drivers/hwtracing/coresight/coresight-etm-perf.c | 105 ++-
 drivers/hwtracing/coresight/coresight-priv.h |   3 +-
 drivers/hwtracing/coresight/coresight.c  |  40 ++---
 include/linux/perf_event.h   |  11 ++-
 include/uapi/linux/perf_event.h  |   1 +
 kernel/events/core.c |  16 
 kernel/events/ring_buffer.c  |   2 +-
 tools/include/uapi/linux/perf_event.h|   1 +
 tools/perf/builtin-record.c  |   9 ++
 tools/perf/util/evlist.c |  24 ++
 tools/perf/util/evlist.h |   3 +
 tools/perf/util/evsel.c  |  33 +++
 tools/perf/util/evsel.h  |   7 ++
 tools/perf/util/parse-events.c   |  76 +++-
 tools/perf/util/parse-events.h   |   1 +
 tools/perf/util/parse-events.l   |  12 +++
 tools/perf/util/parse-events.y   |  11 +++
 19 files changed, 321 insertions(+), 43 deletions(-)

-- 
2.7.4



[PATCH V2 3/6] perf tools: add infrastructure for PMU specific configuration

2016-07-20 Thread Mathieu Poirier
This patchset adds PMU driver specific configuration to the parser
infrastructure by preceding any term with the '@' letter.  As such
doing something like:

perf record -e some_event/@cfg1,@cfg2=config/ ...

will see 'cfg1' and 'cfg2=config' being added to the list of evsel config
terms.  Token 'cfg1' and 'cfg2=config' are not processed in user space
and are meant to be interpreted by the PMU driver.

First the lexer/parser are supplemented with the required definitions to
recognise the driver specific configuration.  From there they are simply
added to the list of event terms.  The bulk of the work is done in
function "parse_events_add_pmu()" where driver config event terms are
added to a new list of driver config terms, which in turn spliced with
the event's new driver configuration list.

Signed-off-by: Mathieu Poirier 
---
 tools/perf/util/evsel.c|  1 +
 tools/perf/util/evsel.h|  4 +++
 tools/perf/util/parse-events.c | 76 +++---
 tools/perf/util/parse-events.h |  1 +
 tools/perf/util/parse-events.l | 12 +++
 tools/perf/util/parse-events.y | 11 ++
 6 files changed, 85 insertions(+), 20 deletions(-)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8c54df61fe64..b16f1621ce3e 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -231,6 +231,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel->bpf_fd  = -1;
INIT_LIST_HEAD(&evsel->node);
INIT_LIST_HEAD(&evsel->config_terms);
+   INIT_LIST_HEAD(&evsel->drv_config_terms);
perf_evsel__object.init(evsel);
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
perf_evsel__calc_id_pos(evsel);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 8a4a6c9f1480..e25fd5e4c740 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -46,6 +46,7 @@ enum {
PERF_EVSEL__CONFIG_TERM_INHERIT,
PERF_EVSEL__CONFIG_TERM_MAX_STACK,
PERF_EVSEL__CONFIG_TERM_OVERWRITE,
+   PERF_EVSEL__CONFIG_TERM_DRV_CFG,
PERF_EVSEL__CONFIG_TERM_MAX,
 };
 
@@ -57,6 +58,7 @@ struct perf_evsel_config_term {
u64 freq;
booltime;
char*callgraph;
+   char*drv_cfg;
u64 stack_user;
int max_stack;
boolinherit;
@@ -79,6 +81,7 @@ struct perf_evsel_config_term {
  *  PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
  *  is used there is an id sample appended to non-sample events
  * @priv:   And what is in its containing unnamed union are tool specific
+ * @drv_config_terms: List of configurables sent directly to the PMU driver
  */
 struct perf_evsel {
struct list_headnode;
@@ -125,6 +128,7 @@ struct perf_evsel {
char*group_name;
boolcmdline_group_boundary;
struct list_headconfig_terms;
+   struct list_headdrv_config_terms;
int bpf_fd;
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6c913c3914fb..697a21c11fc5 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -303,7 +303,8 @@ static struct perf_evsel *
 __add_event(struct list_head *list, int *idx,
struct perf_event_attr *attr,
char *name, struct cpu_map *cpus,
-   struct list_head *config_terms)
+   struct list_head *config_terms,
+   struct list_head *drv_config_terms)
 {
struct perf_evsel *evsel;
 
@@ -322,6 +323,10 @@ __add_event(struct list_head *list, int *idx,
if (config_terms)
list_splice(config_terms, &evsel->config_terms);
 
+   if (drv_config_terms)
+   list_splice(drv_config_terms, &evsel->drv_config_terms);
+
+
list_add_tail(&evsel->node, list);
return evsel;
 }
@@ -330,7 +335,8 @@ static int add_event(struct list_head *list, int *idx,
 struct perf_event_attr *attr, char *name,
 struct list_head *config_terms)
 {
-   return __add_event(list, idx, attr, name, NULL, config_terms) ? 0 : 
-ENOMEM;
+   return __add_event(list, idx, attr, name,
+  NULL, config_terms, NULL) ? 0 : -ENOMEM;
 }
 
 static int parse_aliases(char *str, const char 
*names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -904,6 +910,7 @@ static const char 
*config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
[PARSE_EVENTS__TERM_TYPE_MAX_STACK] = "max-stack",
[PARSE_EVENTS__TERM_TYPE_OVERWRITE] = "overwrite",
[PARSE_EVENTS__TERM_TYPE_NOOVERWRITE]   = "no-overwrite",
+   [PARSE_EVENTS__TERM_TYPE_DRV_CFG]

[PATCH V2 5/6] coresight: adding sink parameter to function coresight_build_path()

2016-07-20 Thread Mathieu Poirier
Up to now function coresight_build_path() was counting on a sink to
have been selected (from sysFS) prior to being called.  This patch
adds a string argument so that a sink matching the argument can be
selected.

Signed-off-by: Mathieu Poirier 
---
 drivers/hwtracing/coresight/coresight-etm-perf.c |  2 +-
 drivers/hwtracing/coresight/coresight-priv.h |  3 +-
 drivers/hwtracing/coresight/coresight.c  | 40 +++-
 3 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c 
b/drivers/hwtracing/coresight/coresight-etm-perf.c
index f4174f36c5a0..f8c7a8733b23 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -184,7 +184,7 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
 * list of devices from source to sink that can be
 * referenced later when the path is actually needed.
 */
-   event_data->path[cpu] = coresight_build_path(csdev);
+   event_data->path[cpu] = coresight_build_path(csdev, NULL);
if (!event_data->path[cpu])
goto err;
}
diff --git a/drivers/hwtracing/coresight/coresight-priv.h 
b/drivers/hwtracing/coresight/coresight-priv.h
index ad975c58080d..3cb574b3cdd9 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -94,7 +94,8 @@ static inline void CS_UNLOCK(void __iomem *addr)
 void coresight_disable_path(struct list_head *path);
 int coresight_enable_path(struct list_head *path, u32 mode);
 struct coresight_device *coresight_get_sink(struct list_head *path);
-struct list_head *coresight_build_path(struct coresight_device *csdev);
+struct list_head *coresight_build_path(struct coresight_device *csdev,
+  const char *sink);
 void coresight_release_path(struct list_head *path);
 
 #ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
diff --git a/drivers/hwtracing/coresight/coresight.c 
b/drivers/hwtracing/coresight/coresight.c
index d08d1ab9bba5..cbbb51a16dff 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -372,30 +372,41 @@ struct coresight_device *coresight_get_sink(struct 
list_head *path)
  * _coresight_build_path - recursively build a path from a @csdev to a sink.
  * @csdev: The device to start from.
  * @path:  The list to add devices to.
+ * @sink:  The name of the sink this path should connect with.
  *
- * The tree of Coresight device is traversed until an activated sink is
- * found.  From there the sink is added to the list along with all the
- * devices that led to that point - the end result is a list from source
- * to sink. In that list the source is the first device and the sink the
- * last one.
+ * The tree of Coresight device is traversed until an activated sink or
+ * the one specified by @sink is found.
+ * From there the sink is added to the list along with all the devices that
+ * led to that point - the end result is a list from source to sink. In that
+ * list the source is the first device and the sink the last one.
  */
 static int _coresight_build_path(struct coresight_device *csdev,
-struct list_head *path)
+struct list_head *path, const char *sink)
 {
int i;
bool found = false;
struct coresight_node *node;
 
-   /* An activated sink has been found.  Enqueue the element */
-   if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
-csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) && csdev->activated)
-   goto out;
+   /*
+* First see if we are dealing with a sink.  If we have one check if
+* it was selected via sysFS or the perf cmd line.
+*/
+   if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
+   csdev->type == CORESIGHT_DEV_TYPE_LINKSINK) {
+   /* Activated via perf cmd line */
+   if (sink && !strcmp(dev_name(&csdev->dev), sink))
+   goto out;
+   /* Activated via sysFS */
+   if (csdev->activated)
+   goto out;
+   }
 
/* Not a sink - recursively explore each port found on this element */
for (i = 0; i < csdev->nr_outport; i++) {
struct coresight_device *child_dev = csdev->conns[i].child_dev;
 
-   if (child_dev && _coresight_build_path(child_dev, path) == 0) {
+   if (child_dev &&
+   _coresight_build_path(child_dev, path, sink) == 0) {
found = true;
break;
}
@@ -422,7 +433,8 @@ out:
return 0;
 }
 
-struct list_head *coresight_build_path(struct coresight_device *cs

[PATCH V2 4/6] perf tools: pushing driver configuration down to the kernel

2016-07-20 Thread Mathieu Poirier
Now that PMU specific driver configuration are queued in
evsel::drv_config_terms, all we need to do is re-use the current
ioctl() mechanism to push down the information to the kernel
driver.

Signed-off-by: Mathieu Poirier 
---
 tools/perf/builtin-record.c |  9 +
 tools/perf/util/evlist.c| 24 
 tools/perf/util/evlist.h|  3 +++
 tools/perf/util/evsel.c | 32 
 tools/perf/util/evsel.h |  3 +++
 5 files changed, 71 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8f2c16d9275f..dffea1033b8e 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -383,6 +383,7 @@ static int record__open(struct record *rec)
struct perf_evlist *evlist = rec->evlist;
struct perf_session *session = rec->session;
struct record_opts *opts = &rec->opts;
+   struct perf_evsel_config_term *err_term;
int rc = 0;
 
perf_evlist__config(evlist, opts, &callchain_param);
@@ -412,6 +413,14 @@ try_again:
goto out;
}
 
+   if (perf_evlist__apply_drv_configs(evlist, &pos, &err_term)) {
+   error("failed to set config \"%s\" on event %s with %d (%s)\n",
+   err_term->val.drv_cfg, perf_evsel__name(pos), errno,
+   strerror_r(errno, msg, sizeof(msg)));
+   rc = -1;
+   goto out;
+   }
+
rc = record__mmap(rec);
if (rc)
goto out;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 2a40b8e1def7..0f485cebae18 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1433,6 +1433,30 @@ int perf_evlist__apply_filters(struct perf_evlist 
*evlist, struct perf_evsel **e
return err;
 }
 
+int perf_evlist__apply_drv_configs(struct perf_evlist *evlist,
+  struct perf_evsel **err_evsel,
+  struct perf_evsel_config_term **err_term)
+{
+   struct perf_evsel *evsel;
+   int err = 0;
+   const int ncpus = cpu_map__nr(evlist->cpus),
+ nthreads = thread_map__nr(evlist->threads);
+
+   evlist__for_each_entry(evlist, evsel) {
+   if (list_empty(&evsel->drv_config_terms))
+   continue;
+
+   err = perf_evsel__apply_drv_configs(evsel, ncpus,
+   nthreads, err_term);
+   if (err) {
+   *err_evsel = evsel;
+   break;
+   }
+   }
+
+   return err;
+}
+
 int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
 {
struct perf_evsel *evsel;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 4fd034f22d2f..bf7ed0be3f33 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -232,6 +232,9 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, 
struct cpu_map *cpus,
   struct thread_map *threads);
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target 
*target);
 int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel 
**err_evsel);
+int perf_evlist__apply_drv_configs(struct perf_evlist *evlist,
+  struct perf_evsel **err_evsel,
+  struct perf_evsel_config_term **term);
 
 void __perf_evlist__set_leader(struct list_head *list);
 void perf_evlist__set_leader(struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index b16f1621ce3e..e5b30d02a5dd 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1035,6 +1035,27 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
return -1;
 }
 
+int perf_evsel__apply_drv_configs(struct perf_evsel *evsel,
+ int ncpus, int nthreads,
+ struct perf_evsel_config_term **err_term)
+{
+   int err = 0;
+   struct perf_evsel_config_term *term;
+
+   list_for_each_entry(term, &evsel->drv_config_terms, list) {
+   err = perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+   PERF_EVENT_IOC_SET_DRV_CONFIGS,
+   (void *)term->val.drv_cfg);
+
+   if (err) {
+   *err_term = term;
+   break;
+   }
+   }
+
+   return err;
+}
+
 int perf_evsel__enable(struct perf_evsel *evsel)
 {
int nthreads = thread_map__nr(evsel->threads);
@@ -1100,6 +1121,16 @@ static void perf_evsel__free_config_terms(struct 
perf_evsel *evsel)
}
 }
 
+static void perf_evsel__free_drv_config_terms(struct perf_evsel *evsel)
+{
+   struct perf_evsel_config_term *term, *h;
+
+   list_for_each_entr

[PATCH V2 6/6] coresight: etm-perf: incorporating sink definition from cmd line

2016-07-20 Thread Mathieu Poirier
Now that PMU specific configuration is available as part of the event,
lookup the sink identified by users from the perf command line and build
a path from source to sink.

With this functionality it is no longer required to select a sink in a
separate step (from sysFS) before a perf trace session can be started.

Signed-off-by: Mathieu Poirier 
---
 drivers/hwtracing/coresight/coresight-etm-perf.c | 101 ++-
 1 file changed, 100 insertions(+), 1 deletion(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c 
b/drivers/hwtracing/coresight/coresight-etm-perf.c
index f8c7a8733b23..5658a7411a66 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -22,6 +22,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -71,11 +72,20 @@ static const struct attribute_group *etm_pmu_attr_groups[] 
= {
 
 static void etm_event_read(struct perf_event *event) {}
 
+static void etm_event_destroy(struct perf_event *event)
+{
+   kfree(event->hw.drv_configs);
+   event->hw.drv_configs = NULL;
+}
+
 static int etm_event_init(struct perf_event *event)
 {
if (event->attr.type != etm_pmu.type)
return -ENOENT;
 
+   event->destroy = etm_event_destroy;
+   event->hw.drv_configs = NULL;
+
return 0;
 }
 
@@ -159,6 +169,7 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
   int nr_pages, bool overwrite)
 {
int cpu;
+   char *cmdl_sink;
cpumask_t *mask;
struct coresight_device *sink;
struct etm_event_data *event_data = NULL;
@@ -171,6 +182,12 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
 
mask = &event_data->mask;
 
+   /*
+* If a sink was specified from the perf cmdline it will be part of
+* the event's drv_configs.
+*/
+   cmdl_sink = (char *)event->hw.drv_configs;
+
/* Setup the path for each CPU in a trace session */
for_each_cpu(cpu, mask) {
struct coresight_device *csdev;
@@ -184,7 +201,7 @@ static void *etm_setup_aux(struct perf_event *event, void 
**pages,
 * list of devices from source to sink that can be
 * referenced later when the path is actually needed.
 */
-   event_data->path[cpu] = coresight_build_path(csdev, NULL);
+   event_data->path[cpu] = coresight_build_path(csdev, cmdl_sink);
if (!event_data->path[cpu])
goto err;
}
@@ -342,6 +359,87 @@ static void etm_event_del(struct perf_event *event, int 
mode)
etm_event_stop(event, PERF_EF_UPDATE);
 }
 
+enum {
+   ETM_TOKEN_SINK_CPU,
+   ETM_TOKEN_SINK,
+   ETM_TOKEN_ERR,
+};
+
+static const match_table_t drv_cfg_tokens = {
+   {ETM_TOKEN_SINK_CPU, "sink=cpu%d:%s"},
+   {ETM_TOKEN_SINK, "sink=%s"},
+   {ETM_TOKEN_ERR, NULL},
+};
+
+static int etm_set_drv_configs(struct perf_event *event, void __user *arg)
+{
+   char *config, *sink = NULL;
+   int cpu = -1, token, ret = 0;
+   substring_t args[MAX_OPT_ARGS];
+
+   /* Only one sink per event */
+   if (event->hw.drv_configs != NULL) {
+   ret = -EINVAL;
+   goto err;
+   }
+
+   /* Make user supplied input usable */
+   config = strndup_user(arg, PAGE_SIZE);
+   if (IS_ERR(config)) {
+   ret = PTR_ERR(config);
+   goto err;
+   }
+
+   /* See above declared @drv_cfg_tokens for the usable formats */
+   token = match_token(config, drv_cfg_tokens, args);
+   switch (token) {
+   case ETM_TOKEN_SINK:
+   /* Just a sink has been specified */
+   sink = match_strdup(&args[0]);
+   if (IS_ERR(sink)) {
+   ret = PTR_ERR(sink);
+   goto err;
+   }
+   break;
+   case ETM_TOKEN_SINK_CPU:
+   /* We have a sink and a CPU */
+
+   /* First get the cpu */
+   if (match_int(&args[0], &cpu)) {
+   ret = -EINVAL;
+   goto err;
+   }
+
+   /* Then the sink */
+   sink = match_strdup(&args[1]);
+   if (IS_ERR(sink)) {
+   ret = PTR_ERR(sink);
+   goto err;
+   }
+   break;
+   default:
+   ret = -EINVAL;
+   goto err;
+   }
+
+   /*
+* If the CPUs don't match the sink is destined to another path.  This
+* isn't as an error hence not setting @ret.
+*/
+   if (event->cpu != cpu)
+   goto err;
+
+   /* We have a valid configuration */
+   event->hw.drv_configs = sink;
+
+out:
+ 

[PATCH V2 2/6] perf: Passing struct perf_event to function setup_aux()

2016-07-20 Thread Mathieu Poirier
Some information, like driver specific configuration, is found
in the hw_perf_event  structure.  As such pass a 'struct perf_event'
to function setup_aux() rather than just the CPU number so that
individual drivers can make the right configuration when setting
up a session.

Signed-off-by: Mathieu Poirier 
Cc: Alexander Shishkin 
---
 arch/x86/events/intel/bts.c  | 4 +++-
 arch/x86/events/intel/pt.c   | 5 +++--
 drivers/hwtracing/coresight/coresight-etm-perf.c | 4 ++--
 include/linux/perf_event.h   | 2 +-
 kernel/events/ring_buffer.c  | 2 +-
 5 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c
index 0a6e393a2e62..98155c2dfcce 100644
--- a/arch/x86/events/intel/bts.c
+++ b/arch/x86/events/intel/bts.c
@@ -68,8 +68,10 @@ static size_t buf_size(struct page *page)
 }
 
 static void *
-bts_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool overwrite)
+bts_buffer_setup_aux(struct perf_event *event, void **pages,
+int nr_pages, bool overwrite)
 {
+   int cpu = event->cpu;
struct bts_buffer *buf;
struct page *page;
int node = (cpu == -1) ? cpu : cpu_to_node(cpu);
diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c
index 04bb5fb5a8d7..5178c5de0b19 100644
--- a/arch/x86/events/intel/pt.c
+++ b/arch/x86/events/intel/pt.c
@@ -1003,10 +1003,11 @@ static int pt_buffer_init_topa(struct pt_buffer *buf, 
unsigned long nr_pages,
  * Return: Our private PT buffer structure.
  */
 static void *
-pt_buffer_setup_aux(int cpu, void **pages, int nr_pages, bool snapshot)
+pt_buffer_setup_aux(struct perf_event *event, void **pages,
+   int nr_pages, bool snapshot)
 {
struct pt_buffer *buf;
-   int node, ret;
+   int node, ret, cpu = event->cpu;
 
if (!nr_pages)
return NULL;
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c 
b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 755125f7917f..f4174f36c5a0 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -155,7 +155,7 @@ static void etm_free_aux(void *data)
schedule_work(&event_data->work);
 }
 
-static void *etm_setup_aux(int event_cpu, void **pages,
+static void *etm_setup_aux(struct perf_event *event, void **pages,
   int nr_pages, bool overwrite)
 {
int cpu;
@@ -163,7 +163,7 @@ static void *etm_setup_aux(int event_cpu, void **pages,
struct coresight_device *sink;
struct etm_event_data *event_data = NULL;
 
-   event_data = alloc_event_data(event_cpu);
+   event_data = alloc_event_data(event->cpu);
if (!event_data)
return NULL;
 
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 59d61a12cf9d..5275b6594989 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -407,7 +407,7 @@ struct pmu {
/*
 * Set up pmu-private data structures for an AUX area
 */
-   void *(*setup_aux)  (int cpu, void **pages,
+   void *(*setup_aux)  (struct perf_event *event, void **pages,
 int nr_pages, bool overwrite);
/* optional */
 
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index ae9b90dc9a5a..56aba90af437 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -616,7 +616,7 @@ int rb_alloc_aux(struct ring_buffer *rb, struct perf_event 
*event,
goto out;
}
 
-   rb->aux_priv = event->pmu->setup_aux(event->cpu, rb->aux_pages, 
nr_pages,
+   rb->aux_priv = event->pmu->setup_aux(event, rb->aux_pages, nr_pages,
 overwrite);
if (!rb->aux_priv)
goto out;
-- 
2.7.4



Re: [PATCH V2 3/6] perf tools: add infrastructure for PMU specific configuration

2016-07-21 Thread Mathieu Poirier
On 21 July 2016 at 01:47, Jiri Olsa  wrote:
> On Wed, Jul 20, 2016 at 02:38:17PM -0600, Mathieu Poirier wrote:
>
> SNIP
>
>> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
>> index d1edbf8cc66a..8d09a976fca8 100644
>> --- a/tools/perf/util/parse-events.h
>> +++ b/tools/perf/util/parse-events.h
>> @@ -71,6 +71,7 @@ enum {
>>   PARSE_EVENTS__TERM_TYPE_MAX_STACK,
>>   PARSE_EVENTS__TERM_TYPE_NOOVERWRITE,
>>   PARSE_EVENTS__TERM_TYPE_OVERWRITE,
>> + PARSE_EVENTS__TERM_TYPE_DRV_CFG,
>>   __PARSE_EVENTS__TERM_TYPE_NR,
>>  };
>>
>> diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
>> index 7a2519435da0..1f7e11a6c5b3 100644
>> --- a/tools/perf/util/parse-events.l
>> +++ b/tools/perf/util/parse-events.l
>> @@ -53,6 +53,16 @@ static int str(yyscan_t scanner, int token)
>>   return token;
>>  }
>>
>> +static int drv_str(yyscan_t scanner, int token)
>> +{
>> + YYSTYPE *yylval = parse_events_get_lval(scanner);
>> + char *text = parse_events_get_text(scanner);
>> +
>> + /* Strip off the '@' */
>> + yylval->str = strdup(text + 1);
>> + return token;
>> +}
>
> why don't let bison parse this with rule like:
>
> | '@' PE_DRV_CFG_TERM
> {
> ...
> }
>
>
> you could omit the drv_str function then

I simply thought it was simple and clean to do it that way - and it
follows the trend already in place.  Are you sure you want me to move
this to bison?  Either way we have to add code...

Many thanks for the review,
Mathieu

>
> thanks,
> jirka


  1   2   3   4   5   6   7   8   9   10   >