| 62 | // --------------------------------------------------------------------------- |
| 63 | |
| 64 | static error_t start(Device* device) { |
| 65 | Device* i2c = device_get_parent(device); |
| 66 | if (device_get_type(i2c) != &I2C_CONTROLLER_TYPE) { |
| 67 | LOG_E(TAG, "Parent is not an I2C controller"); |
| 68 | return ERROR_RESOURCE; |
| 69 | } |
| 70 | |
| 71 | const uint8_t addr = GET_CONFIG(device)->address; |
| 72 | |
| 73 | // M5PM1 enters I2C sleep after inactivity. The first transaction after sleep |
| 74 | // is ignored as the chip wakes up. Retry with increasing delays until ACK. |
| 75 | bool awake = false; |
| 76 | for (int attempt = 0; attempt < 5; attempt++) { |
| 77 | uint8_t chip_id = 0; |
| 78 | if (i2c_controller_register8_get(i2c, addr, REG_DEVICE_ID, &chip_id, TIMEOUT) == ERROR_NONE) { |
| 79 | LOG_I(TAG, "M5PM1 online (chip_id=0x%02X)", chip_id); |
| 80 | awake = true; |
| 81 | break; |
| 82 | } |
| 83 | vTaskDelay(pdMS_TO_TICKS(20 * (attempt + 1))); |
| 84 | } |
| 85 | |
| 86 | if (!awake) { |
| 87 | LOG_E(TAG, "M5PM1 not responding — LCD power will not be enabled"); |
| 88 | return ERROR_NONE; // non-fatal: don't crash the kernel |
| 89 | } |
| 90 | |
| 91 | // Disable I2C idle sleep so the PMIC stays reachable on battery power |
| 92 | if (i2c_controller_register8_set(i2c, addr, REG_I2C_CFG, 0x00, TIMEOUT) != ERROR_NONE) { |
| 93 | LOG_W(TAG, "Failed to disable I2C sleep (non-fatal)"); |
| 94 | } |
| 95 | |
| 96 | // BOOST_EN → EXT_5V / Grove / Hat power rail always on |
| 97 | if (i2c_controller_register8_set_bits(i2c, addr, REG_PWR_CFG, PWR_CFG_BOOST_EN, TIMEOUT) == ERROR_NONE) { |
| 98 | LOG_I(TAG, "EXT_5V boost enabled"); |
| 99 | } else { |
| 100 | LOG_W(TAG, "Failed to enable EXT_5V boost (non-fatal)"); |
| 101 | } |
| 102 | |
| 103 | // PM1_G2 → LCD power enable (L3B rail on StickS3) |
| 104 | // Sequence matches M5GFX: clear FUNC0 bit2, set MODE bit2 output, clear DRV bit2 push-pull, set OUT bit2 high |
| 105 | bool lcd_ok = |
| 106 | i2c_controller_register8_reset_bits(i2c, addr, REG_GPIO_FUNC0, LCD_POWER_BIT, TIMEOUT) == ERROR_NONE && |
| 107 | i2c_controller_register8_set_bits (i2c, addr, REG_GPIO_MODE, LCD_POWER_BIT, TIMEOUT) == ERROR_NONE && |
| 108 | i2c_controller_register8_reset_bits(i2c, addr, REG_GPIO_DRV, LCD_POWER_BIT, TIMEOUT) == ERROR_NONE && |
| 109 | i2c_controller_register8_set_bits (i2c, addr, REG_GPIO_OUT, LCD_POWER_BIT, TIMEOUT) == ERROR_NONE; |
| 110 | |
| 111 | if (lcd_ok) { |
| 112 | LOG_I(TAG, "LCD power enabled via PM1_G2"); |
| 113 | } else { |
| 114 | LOG_E(TAG, "Failed to enable LCD power via PM1_G2"); |
| 115 | } |
| 116 | |
| 117 | // PM1_G3 → speaker amp EN, initially LOW (amp off until audio starts) |
| 118 | bool spk_ok = |
| 119 | i2c_controller_register8_reset_bits(i2c, addr, REG_GPIO_FUNC0, SPEAKER_AMP_FUNC_MASK, TIMEOUT) == ERROR_NONE && |
| 120 | i2c_controller_register8_set_bits (i2c, addr, REG_GPIO_MODE, SPEAKER_AMP_BIT, TIMEOUT) == ERROR_NONE && |
| 121 | i2c_controller_register8_reset_bits(i2c, addr, REG_GPIO_DRV, SPEAKER_AMP_BIT, TIMEOUT) == ERROR_NONE && |
no test coverage detected