This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM3352: Clearing TPS65217 power button interrupt from kernel

Part Number: AM3352
Other Parts Discussed in Thread: TPS65217, AM3354, TPS65218

Tool/software: Linux

Hello,

I'm using a custom board based on am3354 with a 4.9.69 kernel and a tps65217 pmic.

I'm trying to generated an event when I press the power button.

I followed the documentation, but if I add the following line in my dts file, I can see /dev/input/event0 but no event is generated when I press the button.

tps65217-pwrbutton {
compatible = "ti,tps65217-pwrbutton";
interrupts = <2>;
};

However if I change interrupts from 2 to 7 (which is the NMI the PMIC is connected to)

tps65217-pwrbutton {
compatible = "ti,tps65217-pwrbutton";
interrupts = <7>;
};

I can see events on /dev/input/event0 each time I press the button which seems fine.

But in fact the interrupt is never cleared (checked with a scope), so the driver keeps reading the PMIC status register and end up using most of the CPU power...

Did I miss something? Or should I patch the driver to read the INT register on the PMIC to clear the interrupt?

I also tried adding 

interrupt-parent = <&intc>;
interrupts = <7>;	 /* NNMI */

in the &tps block, but if I do that, tps65217-irq drivers masks all interrupts in the PMIC, and I couldn't find how to enable back the Power Button one.

Thanks for your help,

Antoine

  • Antoine,

    We'll get this in front of the right person to advise you and get back to you soon.
  • Hi Antoine,

    I don't know if our kernel config includes the tps65218-powerbutton driver. It may need to be added by menuconfig. Based on this thread: https://e2e.ti.com/support/arm/sitara_arm/f/791/t/641645

    And based on the DT-Bindings doc, interrupt value should be <2>. Please let me know if this solves the CPU usage problem and if it successfully clears the interrupt. 

    Regards,
    Ahmad

  • Hi Ahmad,

    Thank you for your answer. I did enable the tps65218-pwrbutton and try to set interrupt value to <2> at first.
    When I did that, everything looked fine in the kernel, but the interrupt was never triggered.
    So I tried putting interrupt to <7> because the tps65217 on our board is connected to the NMI pin and according to the TRM, NMI is linked to interrupt 7. With that, button detection was working, but the interrupt was never cleared so it lead to very high cpu usage.
    I have the feeling that I should configure the tps65217-irq driver but The documentation is not clear and I don’t know how to configure which interrupt to mask or not (they are all masked by default).

    Hope I explained better.

    Best regards,

    Antoine
  • Hi Antoine,

    You're right, NMI should be 7 and that belongs at the top of the tps node. Then within your tps65217-pwrbutton node you'll use <2> as that is the interrupt in the PMIC. I referenced the beaglebone official kernel repo -- can you try this out? bb-kernel bone dtsi

    Make sure to include "#include <dt-bindings/mfd/tps65217.h>" at the top.

  • Hi Ahmad,

    I tried doing the modificiations you suggested but the file <dt-bindings/mfd/tps65217.h> does not exist in the latest SDK so I replaced the defined by the approriate numbers. I also had to add "

    compatible = "ti,tps65217-pwrbutton";" to have the /dev/input/event0 created.

    Here's how things look like in my dts file:

    /include/ "tps65217.dtsi"
    
    &tps {
    	/*
    	 * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
    	 * mode") at poweroff.  Most BeagleBone versions do not support RTC-only
    	 * mode and risk hardware damage if this mode is entered.
    	 *
    	 * For details, see linux-omap mailing list May 2015 thread
    	 *	[PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
    	 * In particular, messages:
    	 *	www.spinics.net/.../msg118585.html
    	 *	www.spinics.net/.../msg118615.html
    	 *
    	 * You can override this later with
    	 *	&tps {  /delete-property/ ti,pmic-shutdown-controller;  }
    	 * if you want to use RTC-only mode and made sure you are not affected
    	 * by the hardware problems. (Tip: double-check by performing a current
    	 * measurement after shutdown: it should be less than 1 mA.)
    	 */
    
    	ti,pmic-shutdown-controller;
    
    	interrupt-parent = <&intc>;
    	interrupts = <7>;	 /* NNMI */
    
    	regulators {
    		dcdc1_reg: regulator@0 {
    			regulator-name = "vdds_dpr";
    			regulator-always-on;
    		};
    
    		dcdc2_reg: regulator@1 {
    			/* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
    			regulator-name = "vdd_mpu";
    			regulator-min-microvolt = <925000>;
    			regulator-max-microvolt = <1325000>;
    			regulator-boot-on;
    			regulator-always-on;
    		};
    
    		dcdc3_reg: regulator@2 {
    			/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
    			regulator-name = "vdd_core";
    			regulator-min-microvolt = <925000>;
    			regulator-max-microvolt = <1150000>;
    			regulator-boot-on;
    			regulator-always-on;
    		};
    
    		ldo1_reg: regulator@3 {
    			regulator-name = "vio,vrtc,vdds";
    			regulator-always-on;
    		};
    
    		ldo2_reg: regulator@4 {
    			regulator-name = "vdd_3v3aux";
    			regulator-always-on;
    		};
    
    		ldo3_reg: regulator@5 {
    			regulator-name = "vdd_1v8";
    			regulator-always-on;
    		};
    
    		ldo4_reg: regulator@6 {
    			regulator-name = "vdd_3v3a";
    			regulator-always-on;
    		};
    	};
    
    	charger {
    		interrupts = <1>, <0>;
    		interrupts-names = "AC", "USB";
    		status = "okay";
    	};
    
    	pwrbutton {
    		compatible = "ti,tps65217-pwrbutton";
    		interrupts = <2>;
    		status = "okay";
    	};
    };
    

    Unfortunately, if I do that, the interrupt is never triggered (checked with a scope). I'm guessing this has to do with the following lines in "drivers/mfd/tps65217.c" that mask all the interrupts on the tps65217. I couldn't find how to enable them back. I'm guessing one should call the tps65217_irq_enable function, but I don't know how or when to do that.

    static int tps65217_irq_init(struct tps65217 *tps, int irq)
    {
    	int ret;
    
    	mutex_init(&tps->irq_lock);
    	tps->irq = irq;
    
    	/* Mask all interrupt sources */
    	tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
    			| TPS65217_INT_ACM | TPS65217_INT_USBM);
    	tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
    			TPS65217_PROTECT_NONE);
    
    	tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
    		TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
    	if (!tps->irq_domain) {
    		dev_err(tps->dev, "Could not create IRQ domain\n");
    		return -ENOMEM;
    	}
    
    	ret = devm_request_threaded_irq(tps->dev, irq, NULL,
    					tps65217_irq_thread, IRQF_ONESHOT,
    					"tps65217-irq", tps);
    	if (ret) {
    		dev_err(tps->dev, "Failed to request IRQ %d: %d\n",
    			irq, ret);
    		return ret;
    	}
    
    	return 0;
    }
    

    As a reference, please find below the "cat /proc/interrupts" response:

              CPU0
     16:       4732      INTC  68 Level     gp_timer
     19:          1      INTC  78 Level     wkup_m3_txev
     20:        141      INTC  12 Level     49000000.edma_ccint
     22:          0      INTC  14 Level     49000000.edma_ccerrint
     26:          0      INTC  96 Level     44e07000.gpio
     27:          0  44e07000.gpio   0 Edge      rtc-pcf85263
     59:          0      INTC  98 Level     4804c000.gpio
     79:          0  4804c000.gpio  19 Edge      ft6236
     92:          0      INTC  32 Level     481ac000.gpio
    125:          0      INTC  62 Level     481ae000.gpio
    158:        609      INTC  72 Level     44e09000.serial
    159:        650      INTC  73 Level     48022000.serial
    161:        328      INTC  70 Level     44e0b000.i2c
    162:          4      INTC  71 Level     4802a000.i2c
    164:          0      INTC  77 Level     wkup_m3
    170:          0      INTC  75 Level     rtc0
    171:          0      INTC  76 Level     rtc0
    173:          0      INTC   4 Level     48080000.elm
    176:          0      INTC 100 Level     gpmc
    177:          0      INTC 109 Level     53100000.sham
    179:          0      INTC  82 Level     4803c000.mcasp_tx
    180:          0      INTC  83 Level     4803c000.mcasp_rx
    181:          0      INTC 111 Level     48310000.rng
    182:          0      INTC   7 Level     tps65217-irq
    186:          0      INTC   2 Level     tps65217_pwrbutton
    187:        220      INTC  18 Level     musb-hdrc.0
    188:          0      INTC  17 Level     47400000.dma-controller
    Err:          0
    

    I am wondering, since the <dt-bindings/mfd/tps65217.h> is missing in the SDK, maybe some other commits are missing or the way to handle interrupts has changed?

    Thanks for your help,

    Antoine

  • Hi Antoine,

    It looks like there is more to it, I overlooked changes to the tps65217.dtsi as well. After some searching I found the set of patch files that are related to the tps65217 and this power button feature. It seems as if this button driver is primarily driven by the BeagleBoard.org community... reference repo: bb-kernel tps65217 patches

    After manually applying patches 1 through 7 and enabling the TPS65218 button driver with menuconfig, I am able to get /dev/input/event0 to appear. But the interrupts were not registered in /proc/interrupts. I needed to remove the irq_mask code from the PMIC drive as you mentioned. Recompiled the kernel and now when I press the power button I see the interrupt count increase.

    In the BeagleBoard.org kernel the BeagleBone should begin shutdown when the power button is pressed. It seems there is further configuration needed for that to work because with these patches it currently does not trigger any response except for the increasing number in /proc/interrupts. 

  • Thanks Ahmad for pointing me to those patches.

    For the moment, seeing the event in /dev/input/event0 is enough for me, I don't need the kernel to handle things.

    Best Regards,

    Antoine

  • I'm having the very same issue. I can see /dev/input/event0 but no interrupts trigger.

    My relevant dts looks like;

    #include "tps65217.dtsi"
    
    &tps {
            interrupts = <7>; /* NMI */
            interrupt-parent = <&intc>;
    
            ti,pmic-shutdown-controller;
    
            pwrbutton {
                    interrupts = <2>;
                    status = "okay";
            };

    The tps65217.dtsi is:

    &tps {
            compatible = "ti,tps65217";
            interrupt-controller;
    
            pwrbutton {
                    compatible = "ti,tps65217-pwrbutton";
                    status = "disabled";
            };
    

    When I look at /proc/interrupts no interrupts are triggered when I press the power button.

    180:          0      INTC         7 Level     tps65217-irq
    183:          0      tps65217   2 Edge     tps65217_pwrbutton
    

    What irq_masking should be removed in the driver?

     

  • Noel,

    I removed TPS65217_INT_PBM, TPS65217_INT_ACM, and TPS65217_INT_USBM from line 191 from "drivers/mfd/tps65217.c". These interrupts are enabled by default in the PMIC and for some reason the driver masks them all. Also make sure the driver is enabled using menuconfig. 

  • Still the interrupt did not fire. Was this the only change required on kernel 4.69? It seems the the irq types are not matching between driver and dt. Should this patch not have been required for it to work?

  • Looks like that is patch #8 in the list of patches from the beagleboard repo. I did not need to apply that patch for it to work.
  • Hi,

    In the end, what I did is to remove the interrupts = <7> line from the &tps block and put it in the tps65217-pwrbutton one. Here is how my dts looks like now (only relevant parts):

    /include/ "tps65217.dtsi"
    
    &tps {
        /*
         * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
         * mode") at poweroff.  Most BeagleBone versions do not support RTC-only
         * mode and risk hardware damage if this mode is entered.
         *
         * For details, see linux-omap mailing list May 2015 thread
         *  [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
         * In particular, messages:
         *  <a href="www.spinics.net/.../a>
         *  <a href="www.spinics.net/.../a>
         *
         * You can override this later with
         *  &tps {  /delete-property/ ti,pmic-shutdown-controller;  }
         * if you want to use RTC-only mode and made sure you are not affected
         * by the hardware problems. (Tip: double-check by performing a current
         * measurement after shutdown: it should be less than 1 mA.)
         */
    
        ti,pmic-shutdown-controller;
    
        interrupt-parent = <&intc>;
    
        regulators {
            dcdc1_reg: regulator@0 {
                regulator-name = "vdds_dpr";
                regulator-always-on;
            };
    
            dcdc2_reg: regulator@1 {
                /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
                regulator-name = "vdd_mpu";
                regulator-min-microvolt = <925000>;
                regulator-max-microvolt = <1325000>;
                regulator-boot-on;
                regulator-always-on;
            };
    
            dcdc3_reg: regulator@2 {
                /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
                regulator-name = "vdd_core";
                regulator-min-microvolt = <925000>;
                regulator-max-microvolt = <1150000>;
                regulator-boot-on;
                regulator-always-on;
            };
    
            ldo1_reg: regulator@3 {
                regulator-name = "vio,vrtc,vdds";
                regulator-always-on;
            };
    
            ldo2_reg: regulator@4 {
                regulator-name = "vdd_3v3aux";
                regulator-always-on;
            };
    
            ldo3_reg: regulator@5 {
                regulator-name = "vdd_1v8";
                regulator-always-on;
            };
    
            ldo4_reg: regulator@6 {
                regulator-name = "vdd_3v3a";
                regulator-always-on;
            };
        };
    
        pwrbutton {
            compatible = "ti,tps65217-pwrbutton";
            interrupts = <7>;
        };
    };

    then I added a line in /drivers/input/misc/tps65218-pwrbutton.c  to clear the interrupt. Here is how the function looks like now:

    static irqreturn_t tps6521x_pb_irq(int irq, void *_pwr)
    {
    	struct tps6521x_pwrbutton *pwr = _pwr;
    	const struct tps6521x_data *tps_data = pwr->data;
    	unsigned int reg, reg2;
    	int error;
    
    	error = regmap_read(pwr->regmap, tps_data->reg_status, &reg);
            // Reading TPS65217 INT register to clear the interrupt
            error = regmap_read(pwr->regmap, TPS65217_REG_INT, &reg2);
    
    	if (error) {
    		dev_err(pwr->dev, "can't read register: %d\n", error);
    		goto out;
    	}
    	if (reg & tps_data->pb_mask) {
    		input_report_key(pwr->idev, KEY_POWER, 1);
    		pm_wakeup_event(pwr->dev, 0);
    	} else {
    		input_report_key(pwr->idev, KEY_POWER, 0);
    	}
    	input_sync(pwr->idev);
    out:
    	return IRQ_HANDLED;
    }

    With that, kernel does nothing when the interrupt is triggered, but the event shows in /dev/input/event0 so I can handle it in userspace.

    Hope that helps,

    Antoine

    /include/ "tps65217.dtsi"
    &tps {
        /*
         * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
         * mode") at poweroff.  Most BeagleBone versions do not support RTC-only
         * mode and risk hardware damage if this mode is entered.
         *
         * For details, see linux-omap mailing list May 2015 thread
         *  [PATCH] ARM: dts: am335x-bone* enable pmic-shutdown-controller
         * In particular, messages:
         *  <a href="http://www.spinics.net/lists/linux-omap/msg118585.html">www.spinics.net/.../msg118585.html</a>
         *  <a href="http://www.spinics.net/lists/linux-omap/msg118615.html">www.spinics.net/.../msg118615.html</a>
         *
         * You can override this later with
         *  &tps {  /delete-property/ ti,pmic-shutdown-controller;  }
         * if you want to use RTC-only mode and made sure you are not affected
         * by the hardware problems. (Tip: double-check by performing a current
         * measurement after shutdown: it should be less than 1 mA.)
         */
        ti,pmic-shutdown-controller;
        interrupt-parent = <&intc>;
        interrupts = <7>;  /* NNMI */
        regulators {
            dcdc1_reg: regulator@0 {
                regulator-name = "vdds_dpr";
                regulator-always-on;
            };
            dcdc2_reg: regulator@1 {
                /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
                regulator-name = "vdd_mpu";
                regulator-min-microvolt = <925000>;
                regulator-max-microvolt = <1325000>;
                regulator-boot-on;
                regulator-always-on;
            };
            dcdc3_reg: regulator@2 {
                /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
                regulator-name = "vdd_core";
                regulator-min-microvolt = <925000>;
                regulator-max-microvolt = <1150000>;
                regulator-boot-on;
                regulator-always-on;
            };
            ldo1_reg: regulator@3 {
                regulator-name = "vio,vrtc,vdds";
                regulator-always-on;
            };
            ldo2_reg: regulator@4 {
                regulator-name = "vdd_3v3aux";
                regulator-always-on;
            };
            ldo3_reg: regulator@5 {
                regulator-name = "vdd_1v8";
                regulator-always-on;
            };
            ldo4_reg: regulator@6 {
                regulator-name = "vdd_3v3a";
                regulator-always-on;
            };
        };
        charger {
            interrupts = <1>, <0>;
            interrupts-names = "AC", "USB";
            status = "okay";
        };
        pwrbutton {
            compatible = "ti,tps65217-pwrbutton";
            interrupts = <2>;
            status = "okay";
        };
    };