|  | /* | 
|  | * QTest testcase for PowerNV 10 Host I2C Communications | 
|  | * | 
|  | * Copyright (c) 2023, IBM Corporation. | 
|  | * | 
|  | * This work is licensed under the terms of the GNU GPL, version 2 or | 
|  | * later. See the COPYING file in the top-level directory. | 
|  | */ | 
|  | #include "qemu/osdep.h" | 
|  | #include "libqtest.h" | 
|  | #include "hw/gpio/pca9554_regs.h" | 
|  | #include "hw/gpio/pca9552_regs.h" | 
|  | #include "pnv-xscom.h" | 
|  |  | 
|  | #define PPC_BIT(bit)            (0x8000000000000000ULL >> (bit)) | 
|  | #define PPC_BIT32(bit)          (0x80000000 >> (bit)) | 
|  | #define PPC_BIT8(bit)           (0x80 >> (bit)) | 
|  | #define PPC_BITMASK(bs, be)     ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) | 
|  | #define PPC_BITMASK32(bs, be)   ((PPC_BIT32(bs) - PPC_BIT32(be)) | \ | 
|  | PPC_BIT32(bs)) | 
|  |  | 
|  | #define MASK_TO_LSH(m)          (__builtin_ffsll(m) - 1) | 
|  | #define GETFIELD(m, v)          (((v) & (m)) >> MASK_TO_LSH(m)) | 
|  | #define SETFIELD(m, v, val) \ | 
|  | (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m))) | 
|  |  | 
|  | #define PNV10_XSCOM_I2CM_BASE   0xa0000 | 
|  | #define PNV10_XSCOM_I2CM_SIZE   0x1000 | 
|  |  | 
|  | #include "hw/i2c/pnv_i2c_regs.h" | 
|  |  | 
|  | typedef struct { | 
|  | QTestState    *qts; | 
|  | const PnvChip *chip; | 
|  | int           engine; | 
|  | } PnvI2cCtlr; | 
|  |  | 
|  | typedef struct { | 
|  | PnvI2cCtlr  *ctlr; | 
|  | int         port; | 
|  | uint8_t     addr; | 
|  | } PnvI2cDev; | 
|  |  | 
|  |  | 
|  | static uint64_t pnv_i2c_xscom_addr(PnvI2cCtlr *ctlr, uint32_t reg) | 
|  | { | 
|  | return pnv_xscom_addr(ctlr->chip, PNV10_XSCOM_I2CM_BASE + | 
|  | (PNV10_XSCOM_I2CM_SIZE * ctlr->engine) + reg); | 
|  | } | 
|  |  | 
|  | static uint64_t pnv_i2c_xscom_read(PnvI2cCtlr *ctlr, uint32_t reg) | 
|  | { | 
|  | return qtest_readq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg)); | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_xscom_write(PnvI2cCtlr *ctlr, uint32_t reg, uint64_t val) | 
|  | { | 
|  | qtest_writeq(ctlr->qts, pnv_i2c_xscom_addr(ctlr, reg), val); | 
|  | } | 
|  |  | 
|  | /* Write len bytes from buf to i2c device with given addr and port */ | 
|  | static void pnv_i2c_send(PnvI2cDev *dev, const uint8_t *buf, uint16_t len) | 
|  | { | 
|  | int byte_num; | 
|  | uint64_t reg64; | 
|  |  | 
|  | /* select requested port */ | 
|  | reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be); | 
|  | reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port); | 
|  | pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64); | 
|  |  | 
|  | /* check status for cmd complete and bus idle */ | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG); | 
|  | g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0); | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==, | 
|  | I2C_STAT_CMD_COMP); | 
|  |  | 
|  | /* Send start, with stop, with address and len bytes of data */ | 
|  | reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR | I2C_CMD_WITH_STOP; | 
|  | reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr); | 
|  | reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len); | 
|  | pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64); | 
|  |  | 
|  | /* check status for errors */ | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0); | 
|  |  | 
|  | /* write data bytes to fifo register */ | 
|  | for (byte_num = 0; byte_num < len; byte_num++) { | 
|  | reg64 = SETFIELD(I2C_FIFO, 0ull, buf[byte_num]); | 
|  | pnv_i2c_xscom_write(dev->ctlr, I2C_FIFO_REG, reg64); | 
|  | } | 
|  |  | 
|  | /* check status for cmd complete and bus idle */ | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG); | 
|  | g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0); | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==, | 
|  | I2C_STAT_CMD_COMP); | 
|  | } | 
|  |  | 
|  | /* Recieve len bytes into buf from i2c device with given addr and port */ | 
|  | static void pnv_i2c_recv(PnvI2cDev *dev, uint8_t *buf, uint16_t len) | 
|  | { | 
|  | int byte_num; | 
|  | uint64_t reg64; | 
|  |  | 
|  | /* select requested port */ | 
|  | reg64 = SETFIELD(I2C_MODE_BIT_RATE_DIV, 0ull, 0x2be); | 
|  | reg64 = SETFIELD(I2C_MODE_PORT_NUM, reg64, dev->port); | 
|  | pnv_i2c_xscom_write(dev->ctlr, I2C_MODE_REG, reg64); | 
|  |  | 
|  | /* check status for cmd complete and bus idle */ | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG); | 
|  | g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0); | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==, | 
|  | I2C_STAT_CMD_COMP); | 
|  |  | 
|  | /* Send start, with stop, with address and len bytes of data */ | 
|  | reg64 = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR | | 
|  | I2C_CMD_WITH_STOP | I2C_CMD_READ_NOT_WRITE; | 
|  | reg64 = SETFIELD(I2C_CMD_DEV_ADDR, reg64, dev->addr); | 
|  | reg64 = SETFIELD(I2C_CMD_LEN_BYTES, reg64, len); | 
|  | pnv_i2c_xscom_write(dev->ctlr, I2C_CMD_REG, reg64); | 
|  |  | 
|  | /* check status for errors */ | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(reg64 & I2C_STAT_ANY_ERR, ==, 0); | 
|  |  | 
|  | /* Read data bytes from fifo register */ | 
|  | for (byte_num = 0; byte_num < len; byte_num++) { | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_FIFO_REG); | 
|  | buf[byte_num] = GETFIELD(I2C_FIFO, reg64); | 
|  | } | 
|  |  | 
|  | /* check status for cmd complete and bus idle */ | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_EXTD_STAT_REG); | 
|  | g_assert_cmphex(reg64 & I2C_EXTD_STAT_I2C_BUSY, ==, 0); | 
|  | reg64 = pnv_i2c_xscom_read(dev->ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(reg64 & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), ==, | 
|  | I2C_STAT_CMD_COMP); | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9554_default_cfg(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t buf[2]; | 
|  |  | 
|  | /* input register bits are not inverted */ | 
|  | buf[0] = PCA9554_POLARITY; | 
|  | buf[1] = 0; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  |  | 
|  | /* All pins are inputs */ | 
|  | buf[0] = PCA9554_CONFIG; | 
|  | buf[1] = 0xff; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  |  | 
|  | /* Output value for when pins are outputs */ | 
|  | buf[0] = PCA9554_OUTPUT; | 
|  | buf[1] = 0xff; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9554_set_pin(PnvI2cDev *dev, int pin, bool high) | 
|  | { | 
|  | uint8_t send_buf[2]; | 
|  | uint8_t recv_buf[2]; | 
|  | uint8_t mask = 0x1 << pin; | 
|  | uint8_t new_value = ((high) ? 1 : 0) << pin; | 
|  |  | 
|  | /* read current OUTPUT value */ | 
|  | send_buf[0] = PCA9554_OUTPUT; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  |  | 
|  | /* write new OUTPUT value */ | 
|  | send_buf[1] = (recv_buf[0] & ~mask) | new_value; | 
|  | pnv_i2c_send(dev, send_buf, 2); | 
|  |  | 
|  | /* Update config bit for output */ | 
|  | send_buf[0] = PCA9554_CONFIG; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  | send_buf[1] = recv_buf[0] & ~mask; | 
|  | pnv_i2c_send(dev, send_buf, 2); | 
|  | } | 
|  |  | 
|  | static uint8_t pnv_i2c_pca9554_read_pins(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t send_buf[1]; | 
|  | uint8_t recv_buf[1]; | 
|  | send_buf[0] = PCA9554_INPUT; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  | return recv_buf[0]; | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9554_flip_polarity(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t recv_buf[1]; | 
|  | uint8_t send_buf[2]; | 
|  |  | 
|  | send_buf[0] = PCA9554_POLARITY; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  | send_buf[1] = recv_buf[0] ^ 0xff; | 
|  | pnv_i2c_send(dev, send_buf, 2); | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9554_default_inputs(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t pin_values = pnv_i2c_pca9554_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0xff); | 
|  | } | 
|  |  | 
|  | /* Check that setting pin values and polarity changes inputs as expected */ | 
|  | static void pnv_i2c_pca554_set_pins(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t pin_values; | 
|  | pnv_i2c_pca9554_set_pin(dev, 0, 0); | 
|  | pin_values = pnv_i2c_pca9554_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0xfe); | 
|  | pnv_i2c_pca9554_flip_polarity(dev); | 
|  | pin_values = pnv_i2c_pca9554_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0x01); | 
|  | pnv_i2c_pca9554_set_pin(dev, 2, 0); | 
|  | pin_values = pnv_i2c_pca9554_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0x05); | 
|  | pnv_i2c_pca9554_flip_polarity(dev); | 
|  | pin_values = pnv_i2c_pca9554_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0xfa); | 
|  | pnv_i2c_pca9554_default_cfg(dev); | 
|  | pin_values = pnv_i2c_pca9554_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0xff); | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9552_default_cfg(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t buf[2]; | 
|  | /* configure pwm/psc regs */ | 
|  | buf[0] = PCA9552_PSC0; | 
|  | buf[1] = 0xff; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | buf[0] = PCA9552_PWM0; | 
|  | buf[1] = 0x80; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | buf[0] = PCA9552_PSC1; | 
|  | buf[1] = 0xff; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | buf[0] = PCA9552_PWM1; | 
|  | buf[1] = 0x80; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  |  | 
|  | /* configure all pins as inputs */ | 
|  | buf[0] = PCA9552_LS0; | 
|  | buf[1] = 0x55; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | buf[0] = PCA9552_LS1; | 
|  | buf[1] = 0x55; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | buf[0] = PCA9552_LS2; | 
|  | buf[1] = 0x55; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | buf[0] = PCA9552_LS3; | 
|  | buf[1] = 0x55; | 
|  | pnv_i2c_send(dev, buf, 2); | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9552_set_pin(PnvI2cDev *dev, int pin, bool high) | 
|  | { | 
|  | uint8_t send_buf[2]; | 
|  | uint8_t recv_buf[2]; | 
|  | uint8_t reg = PCA9552_LS0 + (pin / 4); | 
|  | uint8_t shift = (pin % 4) * 2; | 
|  | uint8_t mask = ~(0x3 << shift); | 
|  | uint8_t new_value = ((high) ? 1 : 0) << shift; | 
|  |  | 
|  | /* read current LSx value */ | 
|  | send_buf[0] = reg; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  |  | 
|  | /* write new value to LSx */ | 
|  | send_buf[1] = (recv_buf[0] & mask) | new_value; | 
|  | pnv_i2c_send(dev, send_buf, 2); | 
|  | } | 
|  |  | 
|  | static uint16_t pnv_i2c_pca9552_read_pins(PnvI2cDev *dev) | 
|  | { | 
|  | uint8_t send_buf[2]; | 
|  | uint8_t recv_buf[2]; | 
|  | uint16_t inputs; | 
|  | send_buf[0] = PCA9552_INPUT0; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  | inputs = recv_buf[0]; | 
|  | send_buf[0] = PCA9552_INPUT1; | 
|  | pnv_i2c_send(dev, send_buf, 1); | 
|  | pnv_i2c_recv(dev, recv_buf, 1); | 
|  | inputs |= recv_buf[0] << 8; | 
|  | return inputs; | 
|  | } | 
|  |  | 
|  | static void pnv_i2c_pca9552_default_inputs(PnvI2cDev *dev) | 
|  | { | 
|  | uint16_t pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  | g_assert_cmphex(pin_values, ==, 0xffff); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set pins 0-4 one at a time and verify that pins 5-9 are | 
|  | * set to the same value | 
|  | */ | 
|  | static void pnv_i2c_pca552_set_pins(PnvI2cDev *dev) | 
|  | { | 
|  | uint16_t pin_values; | 
|  |  | 
|  | /* set pin 0 low */ | 
|  | pnv_i2c_pca9552_set_pin(dev, 0, 0); | 
|  | pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  |  | 
|  | /* pins 0 and 5 should be low */ | 
|  | g_assert_cmphex(pin_values, ==, 0xffde); | 
|  |  | 
|  | /* set pin 1 low */ | 
|  | pnv_i2c_pca9552_set_pin(dev, 1, 0); | 
|  | pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  |  | 
|  | /* pins 0, 1, 5 and 6 should be low */ | 
|  | g_assert_cmphex(pin_values, ==, 0xff9c); | 
|  |  | 
|  | /* set pin 2 low */ | 
|  | pnv_i2c_pca9552_set_pin(dev, 2, 0); | 
|  | pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  |  | 
|  | /* pins 0, 1, 2, 5, 6 and 7 should be low */ | 
|  | g_assert_cmphex(pin_values, ==, 0xff18); | 
|  |  | 
|  | /* set pin 3 low */ | 
|  | pnv_i2c_pca9552_set_pin(dev, 3, 0); | 
|  | pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  |  | 
|  | /* pins 0, 1, 2, 3, 5, 6, 7 and 8 should be low */ | 
|  | g_assert_cmphex(pin_values, ==, 0xfe10); | 
|  |  | 
|  | /* set pin 4 low */ | 
|  | pnv_i2c_pca9552_set_pin(dev, 4, 0); | 
|  | pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  |  | 
|  | /* pins 0, 1, 2, 3, 5, 6, 7, 8 and 9 should be low */ | 
|  | g_assert_cmphex(pin_values, ==, 0xfc00); | 
|  |  | 
|  | /* reset all pins to the high state */ | 
|  | pnv_i2c_pca9552_default_cfg(dev); | 
|  | pin_values = pnv_i2c_pca9552_read_pins(dev); | 
|  |  | 
|  | /* verify all pins went back to the high state */ | 
|  | g_assert_cmphex(pin_values, ==, 0xffff); | 
|  | } | 
|  |  | 
|  | static void reset_engine(PnvI2cCtlr *ctlr) | 
|  | { | 
|  | pnv_i2c_xscom_write(ctlr, I2C_RESET_I2C_REG, 0); | 
|  | } | 
|  |  | 
|  | static void check_i2cm_por_regs(QTestState *qts, const PnvChip *chip) | 
|  | { | 
|  | int engine; | 
|  | for (engine = 0; engine < chip->num_i2c; engine++) { | 
|  | PnvI2cCtlr ctlr; | 
|  | ctlr.qts = qts; | 
|  | ctlr.chip = chip; | 
|  | ctlr.engine = engine; | 
|  |  | 
|  | /* Check version in Extended Status Register */ | 
|  | uint64_t value = pnv_i2c_xscom_read(&ctlr, I2C_EXTD_STAT_REG); | 
|  | g_assert_cmphex(value & I2C_EXTD_STAT_I2C_VERSION, ==, 0x1700000000); | 
|  |  | 
|  | /* Check for command complete and bus idle in Status Register */ | 
|  | value = pnv_i2c_xscom_read(&ctlr, I2C_STAT_REG); | 
|  | g_assert_cmphex(value & (I2C_STAT_ANY_ERR | I2C_STAT_CMD_COMP), | 
|  | ==, | 
|  | I2C_STAT_CMD_COMP); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void reset_all(QTestState *qts, const PnvChip *chip) | 
|  | { | 
|  | int engine; | 
|  | for (engine = 0; engine < chip->num_i2c; engine++) { | 
|  | PnvI2cCtlr ctlr; | 
|  | ctlr.qts = qts; | 
|  | ctlr.chip = chip; | 
|  | ctlr.engine = engine; | 
|  | reset_engine(&ctlr); | 
|  | pnv_i2c_xscom_write(&ctlr, I2C_MODE_REG, 0x02be040000000000); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void test_host_i2c(const void *data) | 
|  | { | 
|  | const PnvChip *chip = data; | 
|  | QTestState *qts; | 
|  | const char *machine = "powernv8"; | 
|  | PnvI2cCtlr ctlr; | 
|  | PnvI2cDev pca9552; | 
|  | PnvI2cDev pca9554; | 
|  |  | 
|  | if (chip->chip_type == PNV_CHIP_POWER9) { | 
|  | machine = "powernv9"; | 
|  | } else if (chip->chip_type == PNV_CHIP_POWER10) { | 
|  | machine = "powernv10-rainier"; | 
|  | } | 
|  |  | 
|  | qts = qtest_initf("-M %s -smp %d,cores=1,threads=%d -nographic " | 
|  | "-nodefaults -serial mon:stdio -S " | 
|  | "-d guest_errors", | 
|  | machine, SMT, SMT); | 
|  |  | 
|  | /* Check the I2C master status registers after POR */ | 
|  | check_i2cm_por_regs(qts, chip); | 
|  |  | 
|  | /* Now do a forced "immediate" reset on all engines */ | 
|  | reset_all(qts, chip); | 
|  |  | 
|  | /* Check that the status values are still good */ | 
|  | check_i2cm_por_regs(qts, chip); | 
|  |  | 
|  | /* P9 doesn't have any i2c devices attached at this time */ | 
|  | if (chip->chip_type != PNV_CHIP_POWER10) { | 
|  | qtest_quit(qts); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Initialize for a P10 pca9552 hotplug device */ | 
|  | ctlr.qts = qts; | 
|  | ctlr.chip = chip; | 
|  | ctlr.engine = 2; | 
|  | pca9552.ctlr = &ctlr; | 
|  | pca9552.port = 1; | 
|  | pca9552.addr = 0x63; | 
|  |  | 
|  | /* Set all pca9552 pins as inputs */ | 
|  | pnv_i2c_pca9552_default_cfg(&pca9552); | 
|  |  | 
|  | /* Check that all pins of the pca9552 are high */ | 
|  | pnv_i2c_pca9552_default_inputs(&pca9552); | 
|  |  | 
|  | /* perform individual pin tests */ | 
|  | pnv_i2c_pca552_set_pins(&pca9552); | 
|  |  | 
|  | /* Initialize for a P10 pca9554 CableCard Presence detection device */ | 
|  | pca9554.ctlr = &ctlr; | 
|  | pca9554.port = 1; | 
|  | pca9554.addr = 0x25; | 
|  |  | 
|  | /* Set all pca9554 pins as inputs */ | 
|  | pnv_i2c_pca9554_default_cfg(&pca9554); | 
|  |  | 
|  | /* Check that all pins of the pca9554 are high */ | 
|  | pnv_i2c_pca9554_default_inputs(&pca9554); | 
|  |  | 
|  | /* perform individual pin tests */ | 
|  | pnv_i2c_pca554_set_pins(&pca9554); | 
|  |  | 
|  | qtest_quit(qts); | 
|  | } | 
|  |  | 
|  | static void add_test(const char *name, void (*test)(const void *data)) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(pnv_chips); i++) { | 
|  | char *tname = g_strdup_printf("pnv-xscom/%s/%s", name, | 
|  | pnv_chips[i].cpu_model); | 
|  | qtest_add_data_func(tname, &pnv_chips[i], test); | 
|  | g_free(tname); | 
|  | } | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | g_test_init(&argc, &argv, NULL); | 
|  |  | 
|  | add_test("host-i2c", test_host_i2c); | 
|  | return g_test_run(); | 
|  | } |