LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel
User Name
Password
Linux - Kernel This forum is for all discussion relating to the Linux kernel.

Notices


Reply
  Search this Thread
Old 06-13-2024, 02:01 PM   #1
jgrebe
LQ Newbie
 
Registered: Jun 2024
Posts: 7

Rep: Reputation: 0
My power off GPIO linux kernel driver no longer works all the time after upgrading kernel


I have created a gpio shutdown linux kernel driver that drops a gpio pin (kill0) low on shutdown to kill power to the rest of my unit after the computer/kernel is has powered off. It also monitors another gpio (int0) at 100ms that if goes low, will trigger poweroff.

I have created my own function that replaces pm_power_off that drops the gpio pin (kill0) low. In some cases the gpio pin (kill0) is not dropped at is should be. The only options are that the function pm_power_off/test_power_off is not being called or it is being called and for some other reason the gpio is not dropped. I have put my entire shutdown gpio kernel driver below.

HAVE BEEN SCRATCHING MY HEAD FOR DAYS ON THIS ONE Works 95% of the time but I need it to work reliably all the time.

It worked perfect before. Using the same kernel driver, there was no issue with Ubuntu 18.04 kernel version 4.15. I am using Ubuntu 22.04.3 now and kernel version 5.15.0-94.

Here is the main snippet from my gpio driver
Code:
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/pm.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/version.h>
#include <linux/delay.h>


#define POWTEST_VERSION_MACRO(x) #x
#define POWTEST_VERSION_BUILD(x) POWTEST_VERSION_MACRO(x)


#define POWTEST_VERSION_NUM   1.5.0
#define POWTEST_VERSION_STR   POWTEST_VERSION_BUILD(POWTEST_VERSION_NUM)


MODULE_DESCRIPTION("reset-request and power-off support");
MODULE_LICENSE("GPL"); MODULE_VERSION(POWTEST_VERSION_STR);
MODULE_SOFTDEP("pre: i2c-i801 gpio-pca953x");
MODULE_INFO(intree, "Y");


struct gpio_desc* gpiod_int0;       // input:  reset req (active low)
struct gpio_desc* gpiod_kill0;      // output: power off (active low)


static unsigned int0;      // input:  reset req (active low)
static unsigned kill0;     // output: power off (active low)


static struct delayed_work worker;


static void test_power_off(void)
{
    schedule(); /* give kernel a chance to poweroff */
    
    gpiod_set_value_cansleep(gpiod_kill0, 0);


    /* give it some time */
    mdelay( 3000 );
}


static void work(struct work_struct* work)
{
    int rc = -1;


    rc = gpiod_get_raw_value_cansleep(gpiod_int0);


    // power off if reset signal is low
    if(0 == rc) {
        pr_alert("reset request\n");
        orderly_poweroff(false);
    }
    else {
        schedule_delayed_work(&worker, msecs_to_jiffies(100));
    }
}


static struct i2c_board_info pcs9554_info = {
    .type = "pca9554",
    .addr = 0x21,
};


static int cb(struct device* dev, void* opaque)
{
    static const char prefix[] = "SMBus I801";
    struct i2c_adapter* adapter;
    struct i2c_client* client;


    adapter = to_i2c_adapter(dev);
    if(strncmp(adapter->name, prefix, sizeof prefix - 1)) {
        return 0;
    }


    client = i2c_new_client_device(adapter, &pcs9554_info);
    if(!client) {
        return 0;
    }
    return 1;
}


static int cmp(struct gpio_chip* chip, void* data)
{
    if(0 == strcmp(chip->label, data)) {
        return 1;
    }
    else if(('0' <= chip->label[0] && chip->label[0] <= '9') && (0 == strcmp(chip->label + 1, "-0021"))) { /* Workaround for kernel 5.X, when label is "X-0021" */
        return 1;
    }
    return 0;
}


static int __init powtest_init(void)
{
    struct gpio_chip* chip = NULL;


    // find i801 smbus and create device first
    i2c_for_each_dev(0, cb);


    // really "tca0408"
    chip = gpiochip_find("pca9554", cmp);
    if(!chip) {
        return -ENODEV;
    }


    kill0 = chip->base + 0;
    int0  = chip->base + 1;


    gpiod_kill0 = gpio_to_desc(kill0);
    gpiod_int0 = gpio_to_desc(int0);


    pr_info("gpio power %d reset %d\n", kill0, int0);


    // gpio interrupt support not enabled ... poll
    gpio_request(kill0, "kill0");
    gpio_request(int0, "int0");


    gpiod_direction_output_raw(gpiod_kill0, 1);
    gpiod_export(gpiod_kill0, false);


    gpiod_direction_input(gpiod_int0);
    gpiod_export(gpiod_int0, false);


    pm_power_off = test_power_off;


    // start first check now
    INIT_DELAYED_WORK(&worker, work);
    schedule_delayed_work(&worker, msecs_to_jiffies(100));


    return 0;
}


module_init(powtest_init);
 
Old 06-16-2024, 04:51 AM   #2
business_kid
LQ Guru
 
Registered: Jan 2006
Location: Ireland
Distribution: Slackware, Slarm64 & Android
Posts: 16,624

Rep: Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390
I'm a hardware guy, not software.

If the thing works 95% of the time, the software could be working. It might be a dodgy voltage level. As you have gpio pins, and you apparently don't have a pc. can you check the levels? Anything around 0.4V-0.7V could be borderline. Bear in mind also if the current is high, that voltage can vary along a pcb track.
 
Old 06-17-2024, 05:21 AM   #3
business_kid
LQ Guru
 
Registered: Jan 2006
Location: Ireland
Distribution: Slackware, Slarm64 & Android
Posts: 16,624

Rep: Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390
Another thing to try is the kernel config. GPIO is old and may have been deprecated. It was fine on Microcontrollers, where many of the legs are configured as high/low switches Try this line, and if the results from the 2 kernel configs are not the same, post them.
Code:
grep GPIO /path/to/config-<version>
Most distros put the kernel configs in /boot/config-version.
 
Old 06-17-2024, 02:27 PM   #4
jgrebe
LQ Newbie
 
Registered: Jun 2024
Posts: 7

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by business_kid View Post
I'm a hardware guy, not software.

If the thing works 95% of the time, the software could be working. It might be a dodgy voltage level. As you have gpio pins, and you apparently don't have a pc. can you check the levels? Anything around 0.4V-0.7V could be borderline. Bear in mind also if the current is high, that voltage can vary along a pcb track.
We have been actively probing the gpio pins throughout the entire debugging process.

The gpio pin is high at 5V and then in pm_power_off() function call drops low to kill power to rest of the unit. So I do not think it is bad voltage level, it is just that in some cases the voltage never drops.

My thinking is that it has to be some software issue as our hardware has not changed and dkms kernel module for shutdown has not changed. The hardware worked with Ubuntu 18.04 kernel 4.15 but now only works 95% percent of the time with Ubuntu 22.04 kernel version 5.15

The device driver is gpio-pca953x. I also tried downgrading that device driver to what was in kernel 4.15 that we used previously to see if that was the issue but the issue still persists even with the older device driver. This makes me think the issue is coming from some change in linux kernel from 4.15 to 5.15.

Last edited by jgrebe; 06-17-2024 at 03:18 PM.
 
Old 06-17-2024, 03:31 PM   #5
jgrebe
LQ Newbie
 
Registered: Jun 2024
Posts: 7

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by business_kid View Post
Another thing to try is the kernel config. GPIO is old and may have been deprecated. It was fine on Microcontrollers, where many of the legs are configured as high/low switches Try this line, and if the results from the 2 kernel configs are not the same, post them.
Code:
grep GPIO /path/to/config-<version>
Most distros put the kernel configs in /boot/config-version.
Differences from working ubuntu 18, kernel version 4.15 and not-working ubuntu 22, kernel version 5.15. All other config options are the same. ( no setting means that the variable is not set in the file )

kernel version 4.15, ubuntu 18.04
Code:
CONFIG_ARCH_NR_GPIO=(no setting)
CONFIG_MTD_GPIO_ADDR=m
CONFIG_MTD_PHYSMAP_GPIO_ADDR=(no setting)
CONFIG_INPUT_GPIO_TILT_POLLED=m
CONFIG_INPUT_GPIO_VIBRA=(no setting)
CONFIG_SERIAL_MCTRL_GPIO=(no setting)
CONFIG_GPIOLIB_FASTPATH_LIMIT=(no setting)
CONFIG_GPIO_CDEV=(no setting)
CONFIG_GPIO_CDEV_V1=(no setting)
CONFIG_GPIO_AXP209=m
CONFIG_GPIO_LYNXPOINT=y
CONFIG_GPIO_LJCA=(no setting)
CONFIG_GPIO_SIOX=(no setting)
CONFIG_GPIO_AMD_FCH=(no setting)
CONFIG_GPIO_WINBOND=(no setting)
CONFIG_GPIO_M058SSAN=(no setting)
CONFIG_GPIO_PCA953X_IRQ=(no setting)
CONFIG_GPIO_PCA9570=(no setting)
CONFIG_GPIO_CRYSTAL_COVE=m
CONFIG_GPIO_MADERA=(no setting)
CONFIG_GPIO_TQMX86=(no setting)
CONFIG_GPIO_AAEON=(no setting)
CONFIG_GPIO_PCIE_IDIO_24=(no setting)
CONFIG_GPIO_AGGREGATOR=(no setting)
CONFIG_GPIO_VIRTIO=(no setting)
CONFIG_USB_CONN_GPIO=(no setting)
CONFIG_MUX_GPIO=(no setting)
CONFIG_SIOX_BUS_GPIO=(no setting)
CONFIG_FSI_MASTER_GPIO=m
CONFIG_TRACING_EVENTS_GPIO=y
kernel version 5.15, ubuntu 22.04
Code:
CONFIG_ARCH_NR_GPIO=1024
CONFIG_MTD_GPIO_ADDR=(no setting)
CONFIG_MTD_PHYSMAP_GPIO_ADDR=y
CONFIG_INPUT_GPIO_TILT_POLLED=(no setting)
CONFIG_INPUT_GPIO_VIBRA=m
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_CDEV_V1=y
CONFIG_GPIO_AXP209=(no setting)
CONFIG_GPIO_LYNXPOINT=(no setting)
CONFIG_GPIO_LJCA=m
CONFIG_GPIO_SIOX=m
CONFIG_GPIO_AMD_FCH=m
CONFIG_GPIO_WINBOND=m
CONFIG_GPIO_M058SSAN=m
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_PCA9570=m
CONFIG_GPIO_CRYSTAL_COVE=y
CONFIG_GPIO_MADERA=m
CONFIG_GPIO_TQMX86=m
CONFIG_GPIO_AAEON=m
CONFIG_GPIO_PCIE_IDIO_24=m
CONFIG_GPIO_AGGREGATOR=m
CONFIG_GPIO_VIRTIO=m
CONFIG_USB_CONN_GPIO=m
CONFIG_MUX_GPIO=m
CONFIG_SIOX_BUS_GPIO=m
CONFIG_FSI_MASTER_GPIO=(no setting)
CONFIG_TRACING_EVENTS_GPIO=(no setting)
 
Old 06-18-2024, 08:47 AM   #6
jgrebe
LQ Newbie
 
Registered: Jun 2024
Posts: 7

Original Poster
Rep: Reputation: 0
So I just retested our old setup on ubuntu 18, kernel 4.15 and I was suprisingly able to reproduce the issue there as well. Seems like not an issue with the change of kernel version from 4.15 to 5.15 but an issue globally all around.

Are there any fail safes I can setup in the shutdown linux kernel driver that can force a shutdown after some timeout? If the gpio does not drop for whatever reason?
 
Old 06-18-2024, 11:23 AM   #7
business_kid
LQ Guru
 
Registered: Jan 2006
Location: Ireland
Distribution: Slackware, Slarm64 & Android
Posts: 16,624

Rep: Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390
Code:
[sudo] /sbin/shutdown -h <time_in_minutes>
works on most distros. Some may need '-hP' instead. You can also use the halt command, both of which have man pages. Read them.

Tell us what your equipment is. We can only give vague advice if we don't know what you're trying to do, and what your equipment is.
 
Old 06-19-2024, 06:50 AM   #8
jgrebe
LQ Newbie
 
Registered: Jun 2024
Posts: 7

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by business_kid View Post
Code:
[sudo] /sbin/shutdown -h <time_in_minutes>
works on most distros. Some may need '-hP' instead. You can also use the halt command, both of which have man pages. Read them.

Tell us what your equipment is. We can only give vague advice if we don't know what you're trying to do, and what your equipment is.
So we are using
Code:
[sudo] poweroff
to test.

The gpio expander we are using that controls the power kill pins is the PCA9554, it uses the gpio-pca953x linux kernel gpio driver. I have a computer running Ubuntu 22.04.3 LTS with kernel version 5.15. My linux computer is connected to the PCA9554 gpio expander over i2c.
 
Old 06-19-2024, 08:09 AM   #9
jgrebe
LQ Newbie
 
Registered: Jun 2024
Posts: 7

Original Poster
Rep: Reputation: 0
So we did some more testing this morning...

I modified the gpio-pca953x linux kernel driver and utilized the i2c_driver.shutdown callback to set the gpio pin low to kill the circuit. Essentially I moved the control of the gpio pin going low on shutdown from our kernel module override of the "pm_power_off" function to the device driver shutdown callback itself.

This change has seemingly fixed our issue. No issues shutting down anymore. The gpio signal always gets dropped on shutdown.

This makes me think the issue is that the i2c comms are being stopped in some rare cases before we send the drop gpio signal from our kernel module override of "pm_power_off".

Are there any better fixes than this? Any issues with modifying the i2c device driver directly?

Obviously this doesn't leave us the ability to disable this functionality once the device driver is modified lol.
 
Old 06-19-2024, 09:27 AM   #10
business_kid
LQ Guru
 
Registered: Jan 2006
Location: Ireland
Distribution: Slackware, Slarm64 & Android
Posts: 16,624

Rep: Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390Reputation: 2390
If the hardware is so top secret, we can't help you. If it isn't, spill the beans and explain the hardware carefully, particularly the support chips. If you can't do this, mark this thread solved and quietly vanish.

I would also point out that your modification may be bound by the copyleft principle in the GPL. You'd better read the GPL, or get your legal guy to do it.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
When I select restart, my Ubuntu screen goes black but doesnt power off (similar for power off) DiarmuidC111 Linux - Newbie 4 08-24-2023 12:31 PM
Screen power off doesn't power off GPU Geremia Slackware 8 04-27-2021 07:39 PM
GPIO access on a Fujitsu Mini-ITX Industrial Mainboard, PCI Driver for GPIO mechatrix Linux - Embedded & Single-board computer 3 11-20-2011 03:57 PM
Using GPIO (from kernel GPIO support) in MY application DannyGilbert Linux - Kernel 2 03-16-2009 07:52 AM
Power off no longer works davholla Linux - Hardware 13 07-26-2005 12:08 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Software > Linux - Kernel

All times are GMT -5. The time now is 07:34 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration