# PMU HAL Interface Documentation

## Overview

The K230 provides PMU HAL interfaces for handling long-press shutdown procedures in system runtime state, as well as configuring RTC scheduled shutdown/scheduled power-on.

- User-space HAL header file: `src/rtsmart/libs/rtsmart_hal/drivers/pmu/drv_pmu.h`
- User-space HAL implementation: `src/rtsmart/libs/rtsmart_hal/drivers/pmu/drv_pmu.c`
- Reference example: `src/rtsmart/examples/peripheral/pmu/test_pmu.c`

PMU HAL currently mainly covers two types of capabilities:

1. Long-press power key shutdown notification and user-space ACK
1. RTC scheduled shutdown, scheduled power-on (power cycle)

> Note: RTC normal read/write time, normal alarm/tick interrupt configuration belong to RTC device interface capabilities, and are not within the `drv_pmu.h` HAL header file.

---

## Event Model

The long-press shutdown procedure is completed collaboratively by the kernel driver and the user-space HAL:

1. User-space calls `drv_pmu_register_notify()` to register signal notification
1. After the user long-presses the power key and reaches the threshold, the driver reports `DRV_PMU_EVENT_LONG_PRESS`
1. User-space completes cleanup actions such as saving state and unmounting the file system
1. After the user releases the power key, the driver reports `DRV_PMU_EVENT_KEY_RELEASE`
1. User-space calls `drv_pmu_ack_shutdown()` to send ACK
1. The driver performs the actual shutdown after receiving ACK

If user-space does not send ACK, the system will maintain the current running state and will not automatically shut down.

---

## Data Structure Description

### `drv_pmu_inst_t`

**Description**: PMU HAL instance handle, internally encapsulates the `/dev/pmu_pwrkey` device node, signal wait set, and notification registration status. This type is transparent to the user.

### `drv_pmu_event_t`

**Description**: PMU event bitmap type.

### `DRV_PMU_EVENT_LONG_PRESS`

**Description**: Long-press shutdown event detected.

### `DRV_PMU_EVENT_KEY_RELEASE`

**Description**: Power key release event detected after long-press.

---

## Function Interface Description

### `int drv_pmu_inst_create(drv_pmu_inst_t **inst);`

**Function**: Creates a PMU HAL instance and opens `/dev/pmu_pwrkey`.

**Parameters**:

- `inst`: Returns the created PMU instance

**Return Value**:

- `0`: Success
- `-1`: Failure

---

### `void drv_pmu_inst_destroy(drv_pmu_inst_t **inst);`

**Function**: Destroys the PMU HAL instance, automatically unregisters notifications and closes the device.

**Parameters**:

- `inst`: Pointer to the PMU instance pointer

---

### `int drv_pmu_register_notify(drv_pmu_inst_t *inst, int signo);`

**Function**: Registers a PMU event notification.

After successful registration, the driver will send the specified signal to the current process, and user space can wait for and read events via `drv_pmu_wait_event()`.

**Parameters**:

- `inst`: PMU instance
- `signo`: Notification signal number; when less than or equal to `0`, `SIGUSR1` is used by default

**Return Value**:

- `0`: Success
- `-1`: Failure

**Notes**:

- The HAL internally automatically blocks this signal and restores it upon destruction or unregistration
- Repeated calls will first unregister the old notification, then re-register

---

### `int drv_pmu_unregister_notify(drv_pmu_inst_t *inst);`

**Function**: Unregisters the PMU event notification.

**Parameters**:

- `inst`: PMU instance

**Return Value**:

- `0`: Success
- `-1`: Failure

---

### `int drv_pmu_wait_event(drv_pmu_inst_t *inst, drv_pmu_event_t *event, int timeout_ms);`

**Function**: Waits for a PMU event and reads the event bitmap.

**Parameters**:

- `inst`: PMU instance
- `event`: Returned event bitmap
- `timeout_ms`: Wait timeout in ms; a value less than `0` means wait forever

**Return Value**:

- `0`: Event received successfully
- `1`: Timeout, or wait was interrupted by a signal
- `-1`: Failure

**Notes**:

- `drv_pmu_register_notify()` must have been called before this
- On success, the returned event may contain multiple bits simultaneously

---

### `int drv_pmu_ack_shutdown(drv_pmu_inst_t *inst);`

**Function**: Sends a shutdown ACK to the driver.

Usually called after receiving `DRV_PMU_EVENT_KEY_RELEASE`, indicating that user-space cleanup is complete and the system is allowed to shut down.

**Parameters**:

- `inst`: PMU instance

**Return Value**:

- `0`: Success
- `-1`: Failure

---

### `int drv_pmu_schedule_power_cycle(drv_pmu_inst_t *inst, uint32_t shutdown_after_s, uint32_t poweron_after_s);`

**Function**: Configures a one-shot RTC scheduled shutdown/power-on sequence.

The system will shut down after `shutdown_after_s` seconds, and then automatically power on after waiting an additional `poweron_after_s` seconds.

**Parameters**:

- `inst`: PMU instance
- `shutdown_after_s`: Delay time before shutdown, in seconds
- `poweron_after_s`: Delay time before re-powering on, in seconds

**Return Value**:

- `0`: Success
- `-1`: Failure

**Notes**:

- The current driver requires both parameters to typically be no less than `2`
- `poweron_after_s` is counted from the moment of shutdown, not from the moment of calling this interface

---

### `int drv_pmu_cancel_power_cycle(drv_pmu_inst_t *inst);`

**Function**: Cancels the currently configured RTC scheduled shutdown/power-on sequence.

**Parameters**:

- `inst`: PMU instance

**Return Value**:

- `0`: Success
- `-1`: Failure

---

### `int drv_pmu_event_has_long_press(drv_pmu_event_t event);`

**Function**: Checks whether the event bitmap contains a long-press event.

**Parameters**:

- `event`: PMU event bitmap

**Return Value**:

- Non-`0`: Contains `DRV_PMU_EVENT_LONG_PRESS`
- `0`: Does not contain

---

### `int drv_pmu_event_has_key_release(drv_pmu_event_t event);`

**Function**: Checks whether the event bitmap contains a key-release event.

**Parameters**:

- `event`: PMU event bitmap

**Return Value**:

- Non-`0`: Contains `DRV_PMU_EVENT_KEY_RELEASE`
- `0`: Does not contain

---

## Recommended Usage Flow

### Long Press Shutdown Scenario

1. Call `drv_pmu_inst_create()` to create a device handle
1. Call `drv_pmu_register_notify()` to register PMU event notification
1. Call `drv_pmu_wait_event()` in a loop to wait for events
1. Execute user-space cleanup after receiving `DRV_PMU_EVENT_LONG_PRESS`
1. Call `drv_pmu_ack_shutdown()` after receiving `DRV_PMU_EVENT_KEY_RELEASE`
1. Call `drv_pmu_inst_destroy()` to release resources before exit

### RTC Scheduled Power On/Off Scenario

1. Call `drv_pmu_inst_create()` to create a device handle
1. Call `drv_pmu_schedule_power_cycle()` to configure power-off and power-on delays
1. Call `drv_pmu_cancel_power_cycle()` to cancel if needed
1. Call `drv_pmu_inst_destroy()` to release resources after completion

---

## Minimal Example

### Long Press Shutdown Monitoring Example

```c
#include <stdio.h>
#include "drv_pmu.h"

int pmu_wait_shutdown(void)
{
    drv_pmu_inst_t *pmu = NULL;
    drv_pmu_event_t event;

    if (drv_pmu_inst_create(&pmu) < 0)
        return -1;

    if (drv_pmu_register_notify(pmu, 0) < 0)
        goto err;

    for (;;) {
        int ret = drv_pmu_wait_event(pmu, &event, -1);

        if (ret < 0)
            goto err;
        if (ret > 0)
            continue;

        if (drv_pmu_event_has_long_press(event)) {
            /* 执行用户态清理 */
        }

        if (drv_pmu_event_has_key_release(event)) {
            if (drv_pmu_ack_shutdown(pmu) < 0)
                goto err;
            break;
        }
    }

    drv_pmu_inst_destroy(&pmu);
    return 0;

err:
    drv_pmu_inst_destroy(&pmu);
    return -1;
}
```

### RTC Scheduled Power On/Off Example

```c
#include <stdint.h>
#include "drv_pmu.h"

int pmu_schedule_cycle(uint32_t shutdown_after_s, uint32_t poweron_after_s)
{
    drv_pmu_inst_t *pmu = NULL;
    int ret = -1;

    if (drv_pmu_inst_create(&pmu) < 0)
        return -1;

    if (drv_pmu_schedule_power_cycle(pmu,
                                     shutdown_after_s,
                                     poweron_after_s) < 0)
        goto out;

    ret = 0;

out:
    drv_pmu_inst_destroy(&pmu);
    return ret;
}
```

---

## Notes

1. Before use, ensure the system has `RT_USING_RTC_PMU` enabled and that the device node `/dev/pmu_pwrkey` exists.
1. `drv_pmu_wait_event()` relies on the signal notification mechanism; it is recommended to have a dedicated thread uniformly wait for and handle events.
1. `drv_pmu_ack_shutdown()` should be called after receiving `DRV_PMU_EVENT_KEY_RELEASE`.
1. If the application decides not to shut down, it can skip sending the ACK, and the system will continue to run.
1. `drv_pmu_schedule_power_cycle()` depends on the RTC current time being correct; it is recommended to confirm the RTC time has been set before use.
1. The current HAL does not configure the hardware long-press threshold for "long-press to power on after shutdown"; this threshold is determined by the underlying PMU register policy.

---

## Usage Example

Please refer to `src/rtsmart/examples/peripheral/pmu/test_pmu.c`
