It is possible there is a race against the one-second tick. The documentation isn’t entirely clear if the event register must be cleared before a new event can trigger a wakeup. If that is the problem, it should be possible to instead set the RTC alarm some large enough number of seconds into the future.
In terms of Linux implementation, based on the above patch, this sequence would be this, right?
static int da9063_restart_notify(struct notifier_block *this,
unsigned long mode, void *cmd)
{
struct da9063 *da9063 = container_of(this, struct da9063, restart_handler);
regmap_write(da9063->regmap, DA9063_REG_PAGE_CON, 0x00);
regmap_write(da9063->regmap, DA9063_REG_SEQ_B, 0xdf);
regmap_write(da9063->regmap, DA9063_BB_REG_ALARM_MO, 0x20);
regmap_write(da9063->regmap, DA9063_BB_REG_ALARM_Y, 0x80);
regmap_write(da9063->regmap, DA9063_REG_EVENT_A, 0x4);
regmap_write(da9063->regmap, DA9063_REG_CONTROL_A, 0x68);
return NOTIFY_DONE;
}
Edit: updated according to andersm’s comment below
Use the “BB” register definitions to match the datasheet. The “AD” register map is for an old prerelease chip revision.
regmap_write(da9063->regmap, DA9063_BB_REG_ALARM_MO, 0x20);
regmap_write(da9063->regmap, DA9063_BB_REG_ALARM_Y, 0x80);
Thanks, I’m going to try this and leave it in a reboot loop overnight.
- The old sequence powers down the board about half of the time on “reboot”. The other half it does reboot.
- The new sequence does nothing at all. The system just hangs after
reboot: Restarting system. I did enableCONFIG_MFD_DA9063, and have verified that the code gets run by adding a printk.
It’s possible the Linux device drivers configure the PMIC registers in some way that stops it from working. Try the following:
- Completely remove power from the board and let it sit for a few minutes to make sure the PMIC is initialized to the OTP settings
- At the U-boot prompt, try the reset sequence a few times
- Boot to Linux
- Use the reset button to restart the board, preserving the PMIC state
- Try the U-boot sequence again
If it stops working only after booting to Linux, either read the driver sources to figure out what they’re doing, or dump the PMIC registers before and after starting the OS, and see which have changed.
Thank you. That helped me figure it out!
It was indeed a matter of the kernel setting a PMIC register that stopped it from working. It was buried pretty deeply: the initialization for the regmap IRQ chip caused all events to be masked. Once found it was straightforward to work around. Adding
regmap_write(da9063->regmap, DA9063_REG_IRQ_MASK_A, 0x00);
makes it work 100% reliably, here
. Here’s the full patch.
I put this newest sequence in a reboot loop over night, and by morning it had rebooted 282 times without incident. So I concur that this is 100% (or at least >99.6%
) reliable.
Hi guys,
I ported your sequence to a u-boot driver and noticed that, although it works reliably, turning off the board within 16seconds after this sequence is not possible since the board would restart. Weirdly, I did not have this issue when launching the sequence from the u-boot shell: by adding a few sleeps between the register writes in my u-boot driver, it finally worked. It seems the behavior I’m facing is described in the thread shared before (Power Management ICs (PMICs) | Dialog) and I don’t quite understand why it does not happen all the time.
Anyway, as the “sleeps” solution did not suit me, I digged the datasheet and found a shorter sequence that does not give rise to the issue:
i2c dev 0;
i2c mw 0x58 0x13 0x4; // Set the WAKE_UP bit to CONTROL_F
i2c mw 0x58 0xe 0x68; // Powerdown
It works reliably for me, if you have a chance to test this, any feedback is welcome.
That’s neat! I ported that sequence to the kernel hack and it seems to work reliably (only tried about ~10 times for now, manually).
static int da9063_restart_notify(struct notifier_block *this,
unsigned long mode, void *cmd)
{
struct da9063 *da9063 = container_of(this, struct da9063, restart_handler);
regmap_write(da9063->regmap, DA9063_REG_CONTROL_F, 0x04);
regmap_write(da9063->regmap, DA9063_REG_CONTROL_A, 0x68);
return NOTIFY_DONE;
}
I have sent 2 PR to u-boot and linux kernel here:
I’ll keep you posted when/if this gets merged.
Thank you guys,
Alex
I hope so!!! I’m slightly worried about prospects for getting the Linux one merged, according to other posts above reset functionality is supposed to go into opensbi, however that has no I2C driver at all at this point:
Seems like quite a lot of work… at least to add proper I2C infrastructure. Another idea would be to add an fdt_reset_sifive_unmatched.c that hardcodes the I2C controller register write sequence, but not sure that’s more acceptable ![]()
Maybe SiFive wants to carry the patches in https://github.com/sifive/meta-sifive for the meantime.
Those patches are only there to finally have a functional reset on those boards. I’m preparing the proper solution with openSBI i2c driver and Linux using SBI SRST extension, I’ll keep this thread updated 