#include #include #include #include "glasgow.h" // Revision-specific code static uint8_t dac_addr_revabc[] = { I2C_ADDR_IOA_DAC_REVABC012, // (or I2C_ADDR_IOA_DAC_REVC3) I2C_ADDR_IOB_DAC, }; static bool set_vsupply_revabc(uint8_t chan) { // Offset 1650, slope -15.2, 0x1000/15.2 = 269 // The DAC has a 12-bit code word, so we only shift back by 8 uint16_t codeword = (254 << 4) - ((((mgmt_req.vsupply.value[chan] - 1650) >> 4) * 269) >> 4); i2c_sequence sequence[] = { I2C_WRITE(dac_addr_revabc[chan]), I2C_IMM16BE(codeword), I2C_DONE(), }; return i2c_execute(sequence); } static bool get_vsupply_revabc(uint8_t chan) { static __xdata uint16_t codeword; i2c_sequence sequence[] = { I2C_READ(dac_addr_revabc[chan]), I2C_PTR16LE(&codeword), I2C_DONE(), }; if (!i2c_execute(sequence)) return false; // See explanation in `set_vsupply_revabc()`. mgmt_rsp.vsupply.value[chan] = 1650 + (255 - (bswap16(codeword) >> 4)) * 152 / 10; return true; } static bool set_vsupply_revd(uint8_t chan) { return false; } static bool get_vsupply_revd(uint8_t chan) { return false; } // Revision-generic code const uint8_t power_en_bit[] = { 1<= GLASGOW_REV_C3) { // revC3 and later has the port A DAC strapped to a different address because // the address on previous revisions conflicts with SMBus Alert Response address. dac_addr_revabc[0] = I2C_ADDR_IOA_DAC_REVC3; } if (glasgow_config.revision <= GLASGOW_REV_B) { // Strap FXMA outputs as enabled. IO_OEQ_N_REVAB = 1; OED |= (1<valid_mask) return false; for (uint8_t chan = 0; chan < ARRAYSIZE(mgmt_req.vsupply.value); chan++) { uint16_t millivolts = mgmt_req.vsupply.value[chan]; // Check against physical limits. if (!(millivolts == 0 || millivolts >= power_config->vsupply_min && millivolts <= power_config->vsupply_max)) return false; // TODO: Check against programmed limits. } // Apply request. for (uint8_t chan = 0; chan < ARRAYSIZE(mgmt_req.vsupply.value); chan++) { if (mgmt_req.vsupply.mask & (1<set_vsupply(chan)) return false; if (millivolts != 0) IOD |= power_en_bit[chan]; } } return true; } bool power_mgmt_get_vsupply() { mgmt_rsp.vsupply.mask = power_config->valid_mask; for (uint8_t chan = 0; chan < ARRAYSIZE(mgmt_req.vsupply.value); chan++) { if (mgmt_rsp.vsupply.mask & (1<get_vsupply(chan)) return false; } else { mgmt_rsp.vsupply.value[chan] = 0; } } } return true; }