[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 2/4] hw/gpio: add PCA9538 8-bit GPIO expander
From: |
Titus Rwantare |
Subject: |
[PATCH v2 2/4] hw/gpio: add PCA9538 8-bit GPIO expander |
Date: |
Wed, 8 Feb 2023 22:43:37 +0000 |
The 8-bit expander has different register offsets than the 16-bit one,
making them incompatible.
Reviewed-by: Hao Wu <wuhaotsh@google.com>
Signed-off-by: Titus Rwantare <titusr@google.com>
---
hw/gpio/pca_i2c_gpio.c | 94 ++++++++++++++++++++++++++++++++++
include/hw/gpio/pca_i2c_gpio.h | 7 +++
2 files changed, 101 insertions(+)
diff --git a/hw/gpio/pca_i2c_gpio.c b/hw/gpio/pca_i2c_gpio.c
index 434a759453..fa69523556 100644
--- a/hw/gpio/pca_i2c_gpio.c
+++ b/hw/gpio/pca_i2c_gpio.c
@@ -143,6 +143,41 @@ static uint8_t pca6416_recv(I2CSlave *i2c)
return data;
}
+/* slave to master */
+static uint8_t pca9538_recv(I2CSlave *i2c)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+ uint8_t data;
+
+ switch (ps->command) {
+ case PCA9538_INPUT_PORT:
+ data = ps->curr_input;
+ break;
+
+ case PCA9538_OUTPUT_PORT:
+ data = ps->new_output;
+ break;
+
+ case PCA9538_POLARITY_INVERSION_PORT:
+ data = ps->polarity_inv;
+ break;
+
+ case PCA9538_CONFIGURATION_PORT:
+ data = ps->config;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: reading from unsupported register 0x%02x",
+ __func__, ps->command);
+ data = 0xFF;
+ break;
+ }
+
+ trace_pca_i2c_recv(DEVICE(ps)->canonical_path, ps->command, data);
+ return data;
+}
+
/* master to slave */
static int pca6416_send(I2CSlave *i2c, uint8_t data)
{
@@ -203,6 +238,47 @@ static int pca6416_send(I2CSlave *i2c, uint8_t data)
return 0;
}
+/* master to slave */
+static int pca9538_send(I2CSlave *i2c, uint8_t data)
+{
+ PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
+ if (ps->i2c_cmd) {
+ ps->command = data;
+ ps->i2c_cmd = false;
+ return 0;
+ }
+
+ trace_pca_i2c_send(DEVICE(ps)->canonical_path, ps->command, data);
+
+ switch (ps->command) {
+ case PCA9538_INPUT_PORT:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: writing to read only reg: 0x%02x",
+ __func__, ps->command);
+ break;
+ case PCA9538_OUTPUT_PORT:
+ ps->new_output = data;
+ break;
+
+ case PCA9538_POLARITY_INVERSION_PORT:
+ ps->polarity_inv = data;
+ break;
+
+ case PCA9538_CONFIGURATION_PORT:
+ ps->config = data;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: writing to unsupported register\n",
+ __func__);
+ return -1;
+ }
+
+ pca_i2c_update_irqs(ps);
+
+ return 0;
+}
+
static int pca_i2c_event(I2CSlave *i2c, enum i2c_event event)
{
PCAGPIOState *ps = PCA_I2C_GPIO(i2c);
@@ -337,6 +413,19 @@ static void pca6416_gpio_class_init(ObjectClass *klass,
void *data)
k->send = pca6416_send;
}
+static void pca9538_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ PCAGPIOClass *pc = PCA_I2C_GPIO_CLASS(klass);
+
+ dc->desc = "PCA9538 8-bit I/O expander";
+ pc->num_pins = PCA9538_NUM_PINS;
+
+ k->recv = pca9538_recv;
+ k->send = pca9538_send;
+}
+
static void pca_i2c_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -383,6 +472,11 @@ static const TypeInfo pca_gpio_types[] = {
.parent = TYPE_PCA_I2C_GPIO,
.class_init = pca6416_gpio_class_init,
},
+ {
+ .name = TYPE_PCA9538_GPIO,
+ .parent = TYPE_PCA_I2C_GPIO,
+ .class_init = pca9538_gpio_class_init,
+ },
};
DEFINE_TYPES(pca_gpio_types);
diff --git a/include/hw/gpio/pca_i2c_gpio.h b/include/hw/gpio/pca_i2c_gpio.h
index 99322959e1..3ab7d19a97 100644
--- a/include/hw/gpio/pca_i2c_gpio.h
+++ b/include/hw/gpio/pca_i2c_gpio.h
@@ -19,6 +19,7 @@
#define PCA_I2C_MAX_PINS 16
#define PCA6416_NUM_PINS 16
+#define PCA9538_NUM_PINS 8
typedef struct PCAGPIOClass {
I2CSlaveClass parent;
@@ -62,8 +63,14 @@ OBJECT_DECLARE_TYPE(PCAGPIOState, PCAGPIOClass, PCA_I2C_GPIO)
#define PCA6416_CONFIGURATION_PORT_0 0x06 /* read/write */
#define PCA6416_CONFIGURATION_PORT_1 0x07 /* read/write */
+#define PCA9538_INPUT_PORT 0x00 /* read */
+#define PCA9538_OUTPUT_PORT 0x01 /* read/write */
+#define PCA9538_POLARITY_INVERSION_PORT 0x02 /* read/write */
+#define PCA9538_CONFIGURATION_PORT 0x03 /* read/write */
+
#define PCA_I2C_CONFIG_DEFAULT 0
#define TYPE_PCA6416_GPIO "pca6416"
+#define TYPE_PCA9538_GPIO "pca9538"
#endif
--
2.39.1.581.gbfd45094c4-goog