BBB Battery shutdown

576 views
Skip to first unread message

William Hermans

unread,
Apr 16, 2016, 3:55:18 PM4/16/16
to BeagleBoard
When a battery is connected to a beaglebone black, how does the software know to issue a shutdown when power is no longer coming in ? More specifically I'm interested in which file / script performs this action, and what mechanism triggers this behavior.

My intentions are to modify / customize what actually happens when power to the board is battery only.




William Hermans

unread,
Apr 16, 2016, 3:59:35 PM4/16/16
to beagl...@googlegroups.com
Also from what I've read this behavior is different between console and LXDE images. So if this is true I understand that. I do not want the behaviors that each of these images provides, but wish to customize my own.


On Sat, Apr 16, 2016 at 12:55 PM, William Hermans <yyr...@gmail.com> wrote:
When a battery is connected to a beaglebone black, how does the software know to issue a shutdown when power is no longer coming in ? More specifically I'm interested in which file / script performs this action, and what mechanism triggers this behavior.

My intentions are to modify / customize what actually happens when power to the board is battery only.




--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

John Syne

unread,
Apr 16, 2016, 7:33:02 PM4/16/16
to beagl...@googlegroups.com
I’m not sure, but best place to look would be Documentation/power/regulator/charger-management.txt. I believe the PMIC issues event when AC is removed. 

Regards,
John



William Hermans

unread,
Apr 17, 2016, 12:09:29 AM4/17/16
to beagl...@googlegroups.com
Which I pretty much had already figured out this morning right after I posted. Pretty much, the PMIC sees a condition, that needs attention. It writes some values to registers that relate to the given condition, and then sends an NMI out to the am335x processor. Where the am335x processor immediately picks up that the PMIC needs attention( the whole point of an NMI ), reads the register values out of the PMIC to determine what action needs to be taken. Which in the case of the power button being pressed. the am335x issues a shutdown now -h ( Linux ) Which looking at the code, actually seems like the LKM is actually writing to the PMIC registers to do this ?!

Anyway, no idea how a power good condition is being acted on *still*. Meaning, no idea how when a battery is connected, when the external power somehow goes missing. How that particular shutdown is happening, and from where.

William Hermans

unread,
Apr 17, 2016, 5:37:38 PM4/17/16
to beagl...@googlegroups.com
So no one has any idea ? I'm looking for the module, that traps power events, and shuts down the BBB. All I need is a file name. It's pretty hard making sense of the mess that is /drivers/mfd, and the documentation does not seem to be helpful either.

Documentation/power/regulator/charger-management.txt does not exist in my repo, nor in Linus' repo either. There is a similar file, but nothing apparently related to our hardware. Passed that, most of the stuff int the Documentation/power directory seems to be related to ACPI, which again, has nothing to do with even our architecture . . .

John Syne

unread,
Apr 17, 2016, 5:46:04 PM4/17/16
to beagl...@googlegroups.com
Oops, I mistyped: Documentation/power/charger-management.txt. Sorry about that.

Regards,
John




John Syne

unread,
Apr 17, 2016, 6:00:28 PM4/17/16
to beagl...@googlegroups.com

From /kernel/power/poweroff.c
/*
 * When the user hits Sys-Rq o to power down the machine this is the 
 * callback we use
 */
do_poweroff()

Which then call the following sequence:

kernel_power_off() //kernel/reboot.c
machine_power_off() //kernel/reboot.c
pm_power_off() 
omap_rtc_power_off() //drivers/rtc/rtc-omap.c

This is where the power gets turned off. Hopefully this is a good place to start to track down the event that occurs when the AC power is plugged in or removed.

Hope this helps. 

Regards,
John




John Syne

unread,
Apr 17, 2016, 6:07:18 PM4/17/16
to beagl...@googlegroups.com
So in the TPS65217 datasheet, Section 9.3.7, it says in interrupt is generated when pushbutton is pressed/released and USB and AC voltage status change.
Look at the interrupt handler and see how this is implemented.

Regards,
John




John Syne

unread,
Apr 17, 2016, 6:19:20 PM4/17/16
to beagl...@googlegroups.com
The best person to ask would be Nishanth Menon <n...@ti.com> or Anilkumar Ch <anil...@ti.com

Regards,
John




John Syne

unread,
Apr 17, 2016, 6:24:09 PM4/17/16
to beagl...@googlegroups.com
Never mind, I found it.

drivers/mfd/tps65217.c line 164

Regards,
John




John Syne

unread,
Apr 17, 2016, 6:53:43 PM4/17/16
to beagl...@googlegroups.com
I guess I should have read your explanation more closely. OK the interrupt routing issues a key input which replicates the power button being pushed. Not sure if this is what you want, or if you want to stop this from happening when when the AC power is removed.

Regards,
John




William Hermans

unread,
Apr 17, 2016, 6:55:52 PM4/17/16
to beagl...@googlegroups.com
Nothing there at line 164, then on line 165 starts a function. Which contains the code I linked to yesterday. Which is the power push button code. Which again, is not helping . . . So let's walk through that function. Which happens in this order . ..

variable type definitions declarations.
conditional check to find device tree definition node.
test chip_id, return if failure.
attempt and test to allocate memory for the tps object.
attempt to map the tps object to the PMIC registers
mfd device add, and test device add.
attempt to read the PMIC registers, and test return code.

Here it gets a bit fuzzy however, it seems as though the code is attempting to reset the system by setting various register bits in the PMIC ?! I know all about the registers of the PMIC, or rather can find otu what is what really quick by reading the datasheet which I have right in front of me. That is not what I'm having an issue grasping. It seems to me that a shutdown in this manner would not be clean. However, it could be that setting these register bits as such may not cause an immediate power down. *That* is what I find unclear.

/* Set the PMIC to shutdown on PWR_EN toggle */
    if (status_off) {
        ret = tps65217_set_bits(tps, TPS65217_REG_STATUS,
                TPS65217_STATUS_OFF, TPS65217_STATUS_OFF,
                TPS65217_PROTECT_NONE);
        if (ret)
            dev_warn(tps->dev, "unable to set the status OFF\n");
    }

The comment above the code seems to indicate that PWR_EN is causing a shutdown based on being toggle. However, PWR_EN is *NOT* a button, or even a line connected to a button. From the data sheet . . .

PWR_EN

Enable input for DCDC1, 2, 3 converters and LDO1, 2, 3, 4. Pull this pin high to start the
power-up sequence.

 In the schematic, PWR_EN is not connected to any button. Period. The button is connected to PB_IN.

Anyway, the rest of the code is inconsequential.

John Syne

unread,
Apr 17, 2016, 7:02:45 PM4/17/16
to beagl...@googlegroups.com
OK, I see the problem. The file I was looking at is different to the one you linked to. I am using the 4.1.13-ti-r33 kernel, which means that you are missing a patch. Build your own kernel and then look at this file again.

Regards,
John




William Hermans

unread,
Apr 17, 2016, 7:04:36 PM4/17/16
to beagl...@googlegroups.com
I have to say, this code is very painful reading. Every single bit I've read so far is circular code in nature. I've yet to find a bit of code that actually does anything obvious. Meaning, someone has attempted to be clever by creating function, after function that calls yet more functions written by the same author.

So basically you spend all day sifting through worthless code, and potentially never being the wiser . . . Unless these chained functions don't go too deep, and you're actually able to make snese of the code. Before you forget why you started reading the code to begin with . ..

William Hermans

unread,
Apr 17, 2016, 7:05:48 PM4/17/16
to beagl...@googlegroups.com
I'll *NOT* be using a TI kernel, period.

John Syne

unread,
Apr 17, 2016, 7:06:04 PM4/17/16
to beagl...@googlegroups.com
The patched code is easier to read

Regards,
John




John Syne

unread,
Apr 17, 2016, 7:10:40 PM4/17/16
to beagl...@googlegroups.com
static irqreturn_t tps65217_irq(int irq, void *irq_data)
{
struct tps65217 *tps = irq_data;
unsigned int int_reg = 0, status_reg = 0;

tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
tps65217_reg_read(tps, TPS65217_REG_STATUS, &status_reg);
if (status_reg)
dev_dbg(tps->dev, "status now: 0x%X\n", status_reg);

if (!int_reg)
return IRQ_NONE;

if (int_reg & TPS65217_INT_PBI) {
/* Handle push button */
dev_dbg(tps->dev, "power button status change\n");
input_report_key(tps->pwr_but, KEY_POWER,
status_reg & TPS65217_STATUS_PB);
input_sync(tps->pwr_but);
}
if (int_reg & TPS65217_INT_ACI) {
/* Handle AC power status change */
dev_dbg(tps->dev, "AC power status change\n");
/* Press KEY_POWER when AC not present */
input_report_key(tps->pwr_but, KEY_POWER,
~status_reg & TPS65217_STATUS_ACPWR);
input_sync(tps->pwr_but);
}
if (int_reg & TPS65217_INT_USBI) {
/* Handle USB power status change */
dev_dbg(tps->dev, "USB power status change\n");
}

return IRQ_HANDLED;
}

Regards,
John




John Syne

unread,
Apr 17, 2016, 7:19:25 PM4/17/16
to beagl...@googlegroups.com
Apply this patch:

From 51b4d415971bb052a26938791337d1050bf94748 Mon Sep 17 00:00:00 2001
From: Robert Nelson <robert...@gmail.com>
Date: Mon, 26 Oct 2015 11:42:13 -0500
Subject: [PATCH 8/9] tps65217: Enable KEY_POWER press on AC loss / PWR_BUT

This is an adaption to v3.14.x of the original patch by Andrew Bradford <andrew....@omni-id.com>
Some minor devm_* changes and DT support done by Pantelis Antoniou <pa...@antoniou-consulting.com> for 3.8.x

Signed-off-by: Robert Nelson <robert...@gmail.com>
---
 arch/arm/boot/dts/am335x-bone-common.dtsi |   3 +
 drivers/mfd/tps65217.c                    | 122 +++++++++++++++++++++++++++++-
 include/linux/mfd/tps65217.h              |   5 ++
 3 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index 29c0c7e..393af39 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -330,6 +330,9 @@
  */
  ti,pmic-shutdown-controller;
 
+ interrupt-parent = <&intc>;
+ interrupts = <7>; /* NNMI */
+
  regulators {
  dcdc1_reg: regulator@0 {
  regulator-name = "vdds_dpr";
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 7d1cfc1..0730431 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -24,8 +24,12 @@
 #include <linux/slab.h>
 #include <linux/regmap.h>
 #include <linux/err.h>
+#include <linux/input.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps65217.h>
@@ -157,6 +161,82 @@ static const struct of_device_id tps65217_of_match[] = {
  { /* sentinel */ },
 };
 
+static irqreturn_t tps65217_irq(int irq, void *irq_data)
+{
+ struct tps65217 *tps = irq_data;
+ unsigned int int_reg = 0, status_reg = 0;
+
+ tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
+ tps65217_reg_read(tps, TPS65217_REG_STATUS, &status_reg);
+ if (status_reg)
+ dev_dbg(tps->dev, "status now: 0x%X\n", status_reg);
+
+ if (!int_reg)
+ return IRQ_NONE;
+
+ if (int_reg & TPS65217_INT_PBI) {
+ /* Handle push button */
+ dev_dbg(tps->dev, "power button status change\n");
+ input_report_key(tps->pwr_but, KEY_POWER,
+ status_reg & TPS65217_STATUS_PB);
+ input_sync(tps->pwr_but);
+ }
+ if (int_reg & TPS65217_INT_ACI) {
+ /* Handle AC power status change */
+ dev_dbg(tps->dev, "AC power status change\n");
+ /* Press KEY_POWER when AC not present */
+ input_report_key(tps->pwr_but, KEY_POWER,
+ ~status_reg & TPS65217_STATUS_ACPWR);
+ input_sync(tps->pwr_but);
+ }
+ if (int_reg & TPS65217_INT_USBI) {
+ /* Handle USB power status change */
+ dev_dbg(tps->dev, "USB power status change\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int tps65217_probe_pwr_but(struct tps65217 *tps)
+{
+ int ret;
+ unsigned int int_reg;
+
+ tps->pwr_but = devm_input_allocate_device(tps->dev);
+ if (!tps->pwr_but) {
+ dev_err(tps->dev,
+ "Failed to allocated pwr_but input device\n");
+ return -ENOMEM;
+ }
+
+ tps->pwr_but->evbit[0] = BIT_MASK(EV_KEY);
+ tps->pwr_but->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+ tps->pwr_but->name = "tps65217_pwr_but";
+ ret = input_register_device(tps->pwr_but);
+ if (ret) {
+ /* NOTE: devm managed device */
+ dev_err(tps->dev, "Failed to register button device\n");
+ return ret;
+ }
+ ret = devm_request_threaded_irq(tps->dev,
+ tps->irq, NULL, tps65217_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "tps65217", tps);
+ if (ret != 0) {
+ dev_err(tps->dev, "Failed to request IRQ %d\n", tps->irq);
+ return ret;
+ }
+
+ /* enable the power button interrupt */
+ ret = tps65217_reg_read(tps, TPS65217_REG_INT, &int_reg);
+ if (ret < 0) {
+ dev_err(tps->dev, "Failed to read INT reg\n");
+ return ret;
+ }
+ int_reg &= ~TPS65217_INT_PBM;
+ tps65217_reg_write(tps, TPS65217_REG_INT, int_reg, TPS65217_PROTECT_NONE);
+ return 0;
+}
+
 static int tps65217_probe(struct i2c_client *client,
  const struct i2c_device_id *ids)
 {
@@ -164,10 +244,13 @@ static int tps65217_probe(struct i2c_client *client,
  unsigned int version;
  unsigned long chip_id = ids->driver_data;
  const struct of_device_id *match;
+ struct device_node *node;
  bool status_off = false;
+ int irq = -1, irq_gpio = -1;
  int ret;
 
- if (client->dev.of_node) {
+ node = client->dev.of_node;
+ if (node) {
  match = of_match_device(tps65217_of_match, &client->dev);
  if (!match) {
  dev_err(&client->dev,
@@ -175,8 +258,31 @@ static int tps65217_probe(struct i2c_client *client,
  return -EINVAL;
  }
  chip_id = (unsigned long)match->data;
- status_off = of_property_read_bool(client->dev.of_node,
+ status_off = of_property_read_bool(node,
  "ti,pmic-shutdown-controller");
+
+ /* at first try to get irq via OF method */
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ irq = -1;
+ irq_gpio = of_get_named_gpio(node, "irq-gpio", 0);
+ if (irq_gpio >= 0) {
+ /* valid gpio; convert to irq */
+ ret = devm_gpio_request_one(&client->dev,
+ irq_gpio, GPIOF_DIR_IN,
+ "tps65217-gpio-irq");
+ if (ret != 0)
+ dev_warn(&client->dev, "Failed to "
+ "request gpio #%d\n", irq_gpio);
+ irq = gpio_to_irq(irq_gpio);
+ if (irq <= 0) {
+ dev_warn(&client->dev, "Failed to "
+ "convert gpio #%d to irq\n",
+ irq_gpio);
+ irq = -1;
+ }
+ }
+ }
  }
 
  if (!chip_id) {
@@ -200,6 +306,18 @@ static int tps65217_probe(struct i2c_client *client,
  return ret;
  }
 
+ tps->irq = irq;
+ tps->irq_gpio = irq_gpio;
+
+ /* we got an irq, request it */
+ if (tps->irq >= 0) {
+ ret = tps65217_probe_pwr_but(tps);
+ if (ret < 0) {
+ dev_err(tps->dev, "Failed to probe pwr_but\n");
+ return ret;
+ }
+ }
+
  ret = mfd_add_devices(tps->dev, -1, tps65217s,
       ARRAY_SIZE(tps65217s), NULL, 0, NULL);
  if (ret < 0) {
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index ac7fba4..05d24a6 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -257,6 +257,11 @@ struct tps65217 {
  unsigned long id;
  struct regulator_desc desc[TPS65217_NUM_REGULATOR];
  struct regmap *regmap;
+
+ /* Power button and IRQ handling */
+ int irq_gpio; /* might not be set */
+ int irq;
+ struct input_dev *pwr_but;
 };
 
 static inline struct tps65217 *dev_to_tps65217(struct device *dev)
-- 
2.6.2

Regards,
John




William Hermans

unread,
Apr 17, 2016, 7:34:05 PM4/17/16
to beagl...@googlegroups.com
Yeah I recognize that code from source code not written by TI employees. The file is called tps65217_charger.c, and is written by an employee of another company.

Anyway, I think we're going to blow this off. The idea was to wait around without power for 5 minutes, to see if power comes back up. Before issuing a shutdown. Then, on the power up end, using a simple R/C circuit to ramp up voltage to 5v over a specific time period.

By the way, my local source tree is already patched with Robert's BBB patches.

William Hermans

unread,
Apr 17, 2016, 7:53:02 PM4/17/16
to beagl...@googlegroups.com
The real reason why our source trees do not match up. My source tree is based on 4.1.x, and yours seems to be 3.8.x. The patch you showed above would probably botch up my source tree . . .

evilwulfie

unread,
Apr 17, 2016, 8:24:16 PM4/17/16
to beagl...@googlegroups.com
Say you want to use the mcasp0 interface but you don't want to use all
the pins


P9_25 GPIO3_21 Allocated mcasp0_pins AUDIO DIGITAL IN
P9_28 SPI1_CS0 Allocated mcasp0_pins AUDIO DIGITAL OUT
P9_29 SPI1_D0 Allocated mcasp0_pins AUDIO FSK
P9_31 SPI1_SCLK Allocated mcasp0_pins AUDIO B CLOCK


Can these pins be used for GPIO if you set up the pinmux correctly?

P9_27 GPIO3_19 Allocated mcasp0_pins
P9_30 SPI1_D1 Allocated mcasp0_pins
P9_42 GPIO3_18 Allocated mcasp0_pins



---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

John Syne

unread,
Apr 17, 2016, 10:03:11 PM4/17/16
to beagl...@googlegroups.com
Nope, mine is based on 4.1. This patch was adapted by Robert from code that was written for 3.8.

Regards,
John




John Syne

unread,
Apr 17, 2016, 10:11:09 PM4/17/16
to beagl...@googlegroups.com
+ input_report_key(tps->pwr_but, KEY_POWER,
+ ~status_reg & TPS65217_STATUS_ACPWR);
that send a power button pressed as an input key when the AC 5V power is removed. 

Regards,
John




John Syne

unread,
Apr 17, 2016, 10:15:55 PM4/17/16
to beagl...@googlegroups.com
Sorry, that should have read line 75 in the patch file, line 164 in the source code. BTW, this was something I was going to work on but thanks to you I now have a handle on this.

Regards,
John




evilwulfie

unread,
Apr 17, 2016, 10:18:47 PM4/17/16
to beagl...@googlegroups.com
Interesting.  Too bad if you want the battery to act as a UPS it cant some how notify the kernel that AC has been removed
and have a routine to just chill a while to see if power comes back.

Be nice to have a variable that is user settable for the time between loss of AC and shutdown.

As it is now it sees the AC removed, shuts down and no easy way to restart on power restored. Requiring some other IC to monitor power
and then press the pwr_but to restart the processor.




On 4/17/2016 7:10 PM, John Syne wrote:
Yep, it is in the BB kernel:


So again, on line 164 is the Interrupt routing. It is this line:

+ input_report_key(tps->pwr_but, KEY_POWER,

+ ~status_reg & TPS65217_STATUS_ACPWR);
that send a power button pressed as an input key when the AC 5V power is removed. 

Regards,
John




On Apr 17, 2016, at 4:52 PM, William Hermans <yyr...@gmail.com> wrote:

The real reason why our source trees do not match up. My source tree is based on 4.1.x, and yours seems to be 3.8.x. The patch you showed above would probably botch up my source tree . . .

On Sun, Apr 17, 2016 at 4:33 PM, William Hermans <yyr...@gmail.com> wrote:
Yeah I recognize that code from source code not written by TI employees. The file is called tps65217_charger.c, and is written by an employee of another company.

Anyway, I think we're going to blow this off. The idea was to wait around without power for 5 minutes, to see if power comes back up. Before issuing a shutdown. Then, on the power up end, using a simple R/C circuit to ramp up voltage to 5v over a specific time period.




Virus-free. www.avast.com

John Syne

unread,
Apr 17, 2016, 10:39:36 PM4/17/16
to beagl...@googlegroups.com
Yep, you need a hardware state machine to monitor the power source. I don’t use batteries as I use supercaps which are just big enough to power the board during shutdown. When the power returns, I restart the board. There are a few corner cases that occur, such as when the power comes back on during the power down cycle, or the power fails during the power up cycle.

Regards,
John




--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.

John Syne

unread,
Apr 17, 2016, 10:51:10 PM4/17/16
to beagl...@googlegroups.com
One more thing, the power down sequence uses the RTC framework (described earlier in this thread), so it will be possible to set a timer for the shutdown and the wait for the power to return event to cancel the timer. If the power on event does not occur, the shutdown will occur.

Regards,
John




On Apr 17, 2016, at 7:18 PM, evilwulfie <evilw...@gmail.com> wrote:

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.

evilwulfie

unread,
Apr 18, 2016, 1:25:20 AM4/18/16
to beagl...@googlegroups.com
Where in the code do you set that timer ?

For more options, visit https://groups.google.com/d/optout.


Virus-free. www.avast.com

John Syne

unread,
Apr 18, 2016, 1:59:42 AM4/18/16
to beagl...@googlegroups.com
Look at drivers/rtc/rtc-omap.c

omap_rtc_power_off_program()

Regards,
John




William Hermans

unread,
Apr 18, 2016, 2:06:38 AM4/18/16
to beagl...@googlegroups.com
There is no timer in that code. The timer would have to be added, and careful consideration would have to be given to exactly how that was implemented.

So in other words, you would, or should write a completely new kernel module, that is meant to replace what already exists - As an option.

John Syne

unread,
Apr 18, 2016, 11:44:29 AM4/18/16
to beagl...@googlegroups.com
The way I read this is all you have to do is set ALARM2 when the AC line fails. If there is no ALARM2, it switches off 15uS later. 

Regards,
John




John Syne

unread,
Apr 18, 2016, 1:30:10 PM4/18/16
to beagl...@googlegroups.com
I asked Robert how the pwr button is processed and interestingly it is done via udev and systemd. Also, there is some new code going mainstream for the pwr button and battery charger. Perhaps you can implement the timer delay via a custom systemd service. Here is what Robert sent me:

Oh this is finally getting upstreamed:


I need to switch to their version, vs our 3.8.13 erra hack that's been forward ported for years. ;)

Behind the scenes's that patch is reporting a key-event to systemd...


Regards,
John




William Hermans

unread,
Apr 18, 2016, 2:31:26 PM4/18/16
to beagl...@googlegroups.com
#1
william@beaglebone:~$ ls /etc/udev/rules.d/
50-hidraw.rules  50-spi.rules  60-omap-tty.rules  70-persistent-net.rules  uio.rules

#2
We do not care about the button press. We *did* care about what happens when power is removed, while a battery is connected.

Now we do not care. We're not going to bother with it. It's too much hassle for a result that is not really all that important. So what if the power down routine is inefficient . . . it works.

John Syne

unread,
Apr 18, 2016, 3:32:04 PM4/18/16
to beagl...@googlegroups.com
That is OK if this doesn’t work for you, but there are other BBB users who might find this helpful. Currently the powerfail uses the same key function as the pwr button, so the first place to start would be changing the key function to something else. Also, the interrupt routine does not report power good, so that would have to be added. After that, a systemd service could take care of the rest. 

Regards,
John




Mike

unread,
Apr 18, 2016, 5:26:51 PM4/18/16
to beagl...@googlegroups.com
On 04/18/2016 03:31 PM, John Syne wrote:
That is OK if this doesn’t work for you, but there are other BBB users who might find this helpful. Currently the powerfail uses the same key function as the pwr button, so the first place to start would be changing the key function to something else. Also, the interrupt routine does not report power good, so that would have to be added. After that, a systemd service could take care of the rest. 

Regards,
John



I have an interest in this.  It's way above my pay grade from a programming perspective...

Mike

William Hermans

unread,
Apr 18, 2016, 9:26:16 PM4/18/16
to beagl...@googlegroups.com
I have an interest in this.  It's way above my pay grade from a programming perspective...

Mike

Hi Mike,

This is actually something I'm personally very interested in too. However, at this moment in time, my buddy and I are actually in the process of making two different capes for the beaglebone. So this is one of those situations where you have to have priorities . . . and while I obviously do not know everything involved to get this certain thing done, it is not above my pay grade.

So perhaps in the future, it may be something I'll revisit, and would be something I'd contribute back to the community.

William Hermans

unread,
Apr 19, 2016, 6:31:13 PM4/19/16
to beagl...@googlegroups.com
So there is apparently a bug related to this whole situation. Once the input power goes away, whatever it may be. You lose USB, because the PMIC is not longer able to supply 5V. You even get a kernel message in relation to this from musb.

The problem is, once input power is restored, I see no indication that 5V is restored to USB. So If you tail -f /var/log/messages, you'll see one musb message when pulling power, but you will not see a corresponding message when plugging power back in. Additionally if you pull power multiple times. Only the first message is displayed.

What this tells me is that the current kernel modules are not written to deal / handle this yet. So for now, unless I'm wrong ( which i doubt ). It's best just to power down period. After input power goes away, and simply use an R/C network to "time" system up's, in case power goes up / down rapidly. One, or more times consecutively.

William Hermans

unread,
Apr 19, 2016, 6:33:50 PM4/19/16
to beagl...@googlegroups.com
Also, I think ideally, if you need to retain USB during power outages, you would be better off making, or buying a UPS, and using that instead of an on board battery.

John Syne

unread,
Apr 19, 2016, 8:17:08 PM4/19/16
to beagl...@googlegroups.com
In my last e-mail on this issue, I said "Also, the interrupt routine does not report power good, so that would have to be added”. It is a simple thing to add.

Regards,
John




-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.

William Hermans

unread,
Apr 19, 2016, 9:29:16 PM4/19/16
to beagl...@googlegroups.com
Good, now add it.

John Syne

unread,
Apr 19, 2016, 11:51:26 PM4/19/16
to beagl...@googlegroups.com
Here is the problem with that. You use a different kernel to me and you don’t like to use systemd. Hence I will explain how to get this working, but you are going to have to do the coding and testing. To start with, which kernel are you using?

From the TPS65217 datasheet the ACI bit in the INT register (0x02) will be a 1 if the power status changed (either power on or power fail). The state of the power is in the status register (0xA) which is 0 for no power and 1 for power in valid range. So looking at the Interrupt routing, both events are reported. I would recommend changing the input key to something different to KEY_POWER because we do not want to modify the pwr button behavior. 


if (int_reg & TPS65217_INT_ACI) {
/* Handle AC power status change */
dev_dbg(tps->dev, "AC power status change\n");
/* Press KEY_POWER when AC not present */
input_report_key(tps->pwr_but, KEY_POWER,
~status_reg & TPS65217_STATUS_ACPWR);
input_sync(tps->pwr_but);
}

You might have to change input_report_key to input_report_switch as I’m not sure if we can extract the status from EV_KEY.
Using udev, the input key is linked to this systemd service poweroff.target

===
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Power-Off
Documentation=man:systemd.special(7)
DefaultDependencies=no
Requires=systemd-poweroff.service
After=systemd-poweroff.service
AllowIsolate=yes

[Install]
Alias=ctrl-alt-del.target
===

Which in turn runs the systemd-poweroff.service

===
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Power-Off
Documentation=man:systemd-halt.service(8)
DefaultDependencies=no
Requires=shutdown.target umount.target final.target
After=shutdown.target umount.target final.target

[Service]
Type=oneshot
ExecStart=/bin/systemctl --force poweroff
===

Which powers down the board.

So here is what you need to do. When you receive a input key assigned to AC_Power, with a status of fail, start a daemon with a timer. If the timer expires, do the same systemctl poweroff or shutdown -h now. If you get a input key for AC_Power with status of power_good before the timer expires, either kill the daemon or cancel the timer. 

Hope this helps.

Regards,
John




William Hermans

unread,
Apr 20, 2016, 12:28:36 AM4/20/16
to beagl...@googlegroups.com
That's not what I was saying at all. I'm saying if all this is that easy for you, then you should add this functionality, and be the community hero.

This sort of thing is definitely not above my pay grade, but I am not a kernel hacker, and I do not know the file structure all that well. So it would take me a while to to figure out everything I need to know, about everything I'd need. So if this thing is really that easy for you, why don't you make a new LKM, something that takes an argument, or two. LIke g_multi where you pass in a path for the g_mass_storage bit of the driver. Except of course, you want to be able to set a time out for a shutdown.

Second, a kernel module should not require a specific init daemon. That goes against the whole point of Linux.


FYI I could do this entirely in userspace, really easily. Except I would have to poll, instead of using an interrupt, and I pretty much be writing duplicate code, or code that does a duplicate job. But passed that I really do not have to time for this, or to read through, and understand all the required Linux kernel, and LKMs to do this "properly". It's a lot of work for someone who really doesn't know what they're doing.

Lastly, when I say "really easily" I mean that I know it is possible and I know how to go about doing it. I'd just have to research many things to bring it all together. So would also take me a little while. Maybe a week, maybe two. Assuming I had the time.

John Syne

unread,
Apr 20, 2016, 1:15:02 AM4/20/16
to beagl...@googlegroups.com
On Apr 19, 2016, at 9:28 PM, William Hermans <yyr...@gmail.com> wrote:

That's not what I was saying at all. I'm saying if all this is that easy for you, then you should add this functionality, and be the community hero.

This sort of thing is definitely not above my pay grade, but I am not a kernel hacker, and I do not know the file structure all that well. So it would take me a while to to figure out everything I need to know, about everything I'd need. So if this thing is really that easy for you, why don't you make a new LKM, something that takes an argument, or two. LIke g_multi where you pass in a path for the g_mass_storage bit of the driver. Except of course, you want to be able to set a time out for a shutdown.

Second, a kernel module should not require a specific init daemon. That goes against the whole point of Linux.


FYI I could do this entirely in userspace, really easily. Except I would have to poll, instead of using an interrupt, and I pretty much be writing duplicate code, or code that does a duplicate job. But passed that I really do not have to time for this, or to read through, and understand all the required Linux kernel, and LKMs to do this "properly". It's a lot of work for someone who really doesn't know what they're doing.
Yep, it can be done in user space as well. Simply add sigaction to the tps65217 mfd driver. Here is an example of a standalone KM with a user space app. So now we do not use input key, but send events via kernel signals (similar to kill -9 pid or ctrl-c).

Kernel Code:

===
#define SIG_TEST 44 // we choose 44 as our signal number (real-time signals are in the range of 33 to 64)

struct dentry *file;

static ssize_t write_pid(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
{
char mybuf[10];
int pid = 0;
int ret;
struct siginfo info;
struct task_struct *t;
/* read the value from user space */
if(count > 10)
return -EINVAL;
copy_from_user(mybuf, buf, count);
sscanf(mybuf, "%d", &pid);
printk("pid = %d\n", pid);

/* send the signal */
memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIG_TEST;
info.si_code = SI_QUEUE; // this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space,
// and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data
// is not delivered to the user space signal handler function.
info.si_int = 1234;   //real time signals may have 32 bits of data.

rcu_read_lock();
// t = find_task_by_pid_type(PIDTYPE_PID, pid);  //find the task_struct associated with this pid
t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);
if(t == NULL){
printk("no such pid\n");
rcu_read_unlock();
return -ENODEV;
}
rcu_read_unlock();
ret = send_sig_info(SIG_TEST, &info, t);    //send the signal
if (ret < 0) {
printk("error sending signal\n");
return ret;
}
return count;
}

static const struct file_operations my_fops = {
.write = write_pid,
};

static int __init signalexample_module_init(void)
{
/* we need to know the pid of the user space process
  * -> we use debugfs for this. As soon as a pid is written to
  * this file, a signal is sent to that pid
  */
/* only root can write to this file (no read) */
file = debugfs_create_file("signalconfpid", 0200, NULL, NULL, &my_fops);
return 0;
}
static void __exit signalexample_module_exit(void)
{
debugfs_remove(file);

}

===


User Space Code:

===
#define SIG_TEST 44 /* we define our own signal, hard coded since SIGRTMIN is different in user and in kernel space */

void receiveData(int n, siginfo_t *info, void *unused) {
printf("received value %i\n", info->si_int);
}

int main ( int argc, char **argv )
{
int configfd;
char buf[10];
/* setup the signal handler for SIG_TEST
  * SA_SIGINFO -> we want the signal handler function with 3 arguments
  */
struct sigaction sig;
sig.sa_sigaction = receiveData;
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);

/* kernel needs to know our pid to be able to send us a signal ->
  * we use debugfs for this -> do not forget to mount the debugfs!
  */
configfd = open("/sys/kernel/debug/signalconfpid", O_WRONLY);
if(configfd < 0) {
perror("open");
return -1;
}
sprintf(buf, "%i", getpid());
if (write(configfd, buf, strlen(buf) + 1) < 0) {
perror("fwrite");
return -1;
}

return 0;
}
===

William Hermans

unread,
Apr 20, 2016, 3:46:00 AM4/20/16
to beagl...@googlegroups.com
Well that is not how I'd do things, and I suppose that code if complete and integrated into the tps65217.c file, it might work . . .

But as I said that code is not complete, and is what looks like example code out of some Documentation/*txt file.

John Syne

unread,
Apr 20, 2016, 3:59:59 AM4/20/16
to beagl...@googlegroups.com
I just don’t understand what you are asking for. The code is self explanatory and with a little effort, you can make it work. My guess is you want me to add the include headers and create the Makefile and Kconfig files. If that is what you want, I can do it for you, but I thought you would know how to do this yourself. Take a book and read about sigaction. I’m sure you will find examples just like the ones I sent you. I’ve pulled code like this together for year to understand how comms works between the kernel and user space.  

Regards,
John




William Hermans

unread,
Apr 20, 2016, 4:18:08 AM4/20/16
to beagl...@googlegroups.com
I just don’t understand what you are asking for. The code is self explanatory and with a little effort, you can make it work. My guess is you want me to add the include headers and create the Makefile and Kconfig files. If that is what you want, I can do it for you, but I thought you would know how to do this yourself. Take a book and read about sigaction. I’m sure you will find examples just like the ones I sent you. I’ve pulled code like this together for year to understand how comms works between the kernel and user space.  
Regards,
John
Dont do it for me, because I do not need it. Do it for all those interested people you mentioned before.

You say it's easy, and you're pasting in random code here in there, but I've yet to see you come up with a real, and solid solution. You keep talking around the subject like it's simple . . .so put your money where your mouth is.

Either that, or stop "talking", because you're not helping anyone.


John Syne

unread,
Apr 20, 2016, 4:48:12 AM4/20/16
to beagl...@googlegroups.com
What a shitty attitude. I don’t mind helping people out who appreciate the help, but why would anyone help you when you all you do is complain about the help. 

Regards,
John




William Hermans

unread,
Apr 20, 2016, 12:40:14 PM4/20/16
to beagl...@googlegroups.com
What a shitty attitude. I don’t mind helping people out who appreciate the help, but why would anyone help you when you all you do is complain about the help. 
Regards,
John
It's not just anyone who gets this special treatment. Just you. I dont like you, have told you this repeatedly and yet you feel compelled to inject yourself into discussions I start, or participate in. I even told you I would have nothing further to say to you ever. And you again felt compelled to inject yourself into this discussion.

But hey, who knows, maybe someday you'll get the hint.


John Syne

unread,
Apr 20, 2016, 1:50:57 PM4/20/16
to beagl...@googlegroups.com
Yep, perfectly clear. You are a hater and there is no hope for you. Strange how the few conflicts on this forum have always involved you as one of the parties. I don’t recall any other conflicts that did not involve you. Perhaps you need professional help to get over your anger issues. Anyway, good luck to you.

Regards,
John




William Hermans

unread,
Apr 20, 2016, 2:26:59 PM4/20/16
to beagl...@googlegroups.com
I'm a hater of people who consistently have to have the last word on a subject they obviously know nothing about. All you did to this discussion was create confusion, and yet another rabbit hole to explore. You have not even answered my original question, and you do not even realize it.

William Hermans

unread,
Apr 20, 2016, 2:35:02 PM4/20/16
to beagl...@googlegroups.com
I think my house mate put it perfectly.

He seems like a smart person who knows hows to copy / paste text. Ignore him.

bmel...@gmail.com

unread,
Aug 10, 2016, 3:28:01 PM8/10/16
to BeagleBoard
Hello John,

I've read through this thread and am very interested in solving this problem (with your help) and posting the solution if  successful. My goal is to switch to battery power without a shut down when AC power is removed. Currently, the kernel treats the removal of AC power as if the power button is pressed and a clean shut-down is issued. I'm using Mentorel's Beaglebone uSomIQ v4  which is a ruggedized version of the BBB and have installed the 3.8.18-bone79 kernel and running Debian 11.

Where can I find the code you posted that needs to be modified? Specifically:


if (int_reg & TPS65217_INT_ACI) {
/* Handle AC power status change */
dev_dbg(tps->dev, "AC power status change\n");
/* Press KEY_POWER when AC not present */
input_report_key(tps->pwr_but, KEY_POWER,
~status_reg & TPS65217_STATUS_ACPWR);
input_sync(tps->pwr_but);
}

I do not see any "tps65217" source files. A find -name *tps65217* returns:

root@beaglebone:/# find -name *tps65217*
./usr/src/linux-headers-3.8.13-bone79/include/linux/mfd/tps65217.h
./usr/src/linux-headers-3.8.13-bone79/include/config/backlight/tps65217.h
./usr/src/linux-headers-3.8.13-bone79/include/config/mfd/tps65217.h
./usr/src/linux-headers-3.8.13-bone79/include/config/regulator/tps65217.h
./sys/bus/i2c/drivers/tps65217
./sys/bus/platform/devices/tps65217-pmic
./sys/bus/platform/devices/tps65217-bl
./sys/bus/platform/drivers/tps65217-pmic
./sys/bus/platform/drivers/tps65217-pmic/tps65217-pmic
./sys/bus/platform/drivers/tps65217-bl
./sys/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024/tps65217-pmic
./sys/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024/tps65217-bl
./proc/irq/7/tps65217
./root/boneDeviceTree/DTSource3.8.12/tps65217.dtsi
./root/boneDeviceTree/DTSource3.8.13/tps65217.dtsi
./root/boneDeviceTree/DTSource3.8.11/tps65217.dtsi

Thank you,

Bolek

Robert Nelson

unread,
Aug 10, 2016, 3:35:15 PM8/10/16
to Beagle Board, bmel...@gmail.com
On Wed, Aug 10, 2016 at 12:29 PM, <bmel...@gmail.com> wrote:
Hello John,

I've read through this thread and am very interested in solving this problem (with your help) and posting the solution if  successful. My goal is to switch to battery power without a shut down when AC power is removed. Currently, the kernel treats the removal of AC power as if the power button is pressed and a clean shut-down is issued. I'm using Mentorel's Beaglebone uSomIQ v4  which is a ruggedized version of the BBB and have installed the 3.8.18-bone79 kernel and running Debian 11.

Where can I find the code you posted that needs to be modified? Specifically:

if (int_reg & TPS65217_INT_ACI) {
/* Handle AC power status change */
dev_dbg(tps->dev, "AC power status change\n");
/* Press KEY_POWER when AC not present */
input_report_key(tps->pwr_but, KEY_POWER,
~status_reg & TPS65217_STATUS_ACPWR);
input_sync(tps->pwr_but);
}

Robert Nelson

unread,
Aug 10, 2016, 4:40:00 PM8/10/16
to Beagle Board, Bolek Mellerowicz
On Wed, Aug 10, 2016 at 3:34 PM, Bolek Mellerowicz <bmel...@gmail.com> wrote:
> Hi Robert,
>
> Thank you for the links. I think I may need a bit of guidance:
>
> 1) Since I was not able to locate the tps65217.c file on my BBB
> (3.8.13-bone79), am I supposed to modify the code in the second link you
> provided and then compile and deploy the driver on to my existing kernel?
>
> 2) Will I need to build and download a new kernel using your first link? If
> so, would I lose my own files and third party libraries that are currently
> on my existing kernel?
>
> Btw, I found this pdf explaining how to build the kernel and how to build &
> deploy drivers.

Correct, it's a "built-in" kernel module, so if you want to modify it,
you'll have to rebuild the kernel..

William Hermans

unread,
Aug 10, 2016, 4:51:05 PM8/10/16
to beagl...@googlegroups.com
My solution was easier i thought.

Uninstall acpid
william@beaglebone:~$ cat /proc/interrupts
           CPU0
 . . .
197:          1      INTC   7 Level     tps65217
. . .

Then when a battery is connected to the board through the 4 test points, and the board loses DC input, or the power button is cycles this file:

william@beaglebone:~$ cat /proc/irq/197/spurious
count 0
unhandled 0
last_unhandled 0 ms

count will increment.

However I've not yet tested this on a 3.8.x kernel. But at one point I did have this working on a 4.x image. I have not tested recently however( within the last few months ). At least one caveat that I can think of off hand however. The irq number changes from system to system. So additional string parsing would have to be done to find the actual file programmatically. But not impossible.

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/CAOCHtYheMTtCe4Hc4iEOu_49%3DHKsEGM1ROg2P5p0bMqtB80C8Q%40mail.gmail.com.

John Syne

unread,
Aug 10, 2016, 8:49:59 PM8/10/16
to Beagle Board, Bolek Mellerowicz
Hi Bolek,

I’m traveling so I don’t have access to my development system. The code I was referring to is V4.1 which will be different from the V3.8.13 kernel you are using. To start with, you have to download the kernel source code and if you are using an older kernel, you should use this repo:


Follow the instructions on how to build the kernel you need.

Next, you will find the kernel source code in the KERNEL folder.

In that folder, do the following:

git grep TPS65217_INT_ACI

That will list all the source files that reference this term.

My guess it would be something like drivers/mfd/tps65217.c

Doing a quick search, it looks like this gets added by a patch:


This is the wrong repo, but there should be something similar in the /patches folder. 

I apologize for not giving you the exact links, but I am doing this mainly from memory and a quick google search.

Regards,
John




On Aug 10, 2016, at 1:08 PM, Bolek Mellerowicz <bmel...@gmail.com> wrote:

Hi John,

I posted a message on the BBB Battery shutdown thread but am not sure if my post got through.  After searching for a while and reading the thread I see no one has actually solved this issue where removal of AC power is interpreted by the kernel as a power button press which causes a clean shut-down. My goal is have the BBB continue to run on BAT power when AC is removed AND at the same time teach myself a bit more about the kernel and embedded linux in general. In return, I promise to contribute to your thread which hopefully leads to a solution.

The kernel I installed is 3.8.13-bone79 with Debian 11 running. I am using a ruggedized version of the BBB board: Mentorel Beaglebone uSomIQ.

In your thread, you pointed to the following code which would need to be modified:

if (int_reg & TPS65217_INT_ACI) {
        /* Handle AC power status change */
        dev_dbg(tps->dev, "AC power status change\n");
        /* Press KEY_POWER when AC not present */
        input_report_key(tps->pwr_but, KEY_POWER,
                        ~status_reg & TPS65217_STATUS_ACPWR);
        input_sync(tps->pwr_but);
}
Where can I find this source code? A find -name *tps65217* on my Beagle returns:


root@beaglebone:/# find -name *tps65217*
./usr/src/linux-headers-3.8.13-bone79/include/linux/mfd/tps65217.h
./usr/src/linux-headers-3.8.13-bone79/include/config/backlight/tps65217.h
./usr/src/linux-headers-3.8.13-bone79/include/config/mfd/tps65217.h
./usr/src/linux-headers-3.8.13-bone79/include/config/regulator/tps65217.h
./sys/bus/i2c/drivers/tps65217
./sys/bus/platform/devices/tps65217-pmic
./sys/bus/platform/devices/tps65217-bl
./sys/bus/platform/drivers/tps65217-pmic
./sys/bus/platform/drivers/tps65217-pmic/tps65217-pmic
./sys/bus/platform/drivers/tps65217-bl
./sys/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024/tps65217-pmic
./sys/devices/ocp.3/44e0b000.i2c/i2c-0/0-0024/tps65217-bl
./proc/irq/7/tps65217
./root/boneDeviceTree/DTSource3.8.12/tps65217.dtsi
./root/boneDeviceTree/DTSource3.8.13/tps65217.dtsi
./root/boneDeviceTree/DTSource3.8.11/tps65217.dtsi

Kind regards,

Bolek

Reply all
Reply to author
Forward
0 new messages