[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/3] hw/gpio: add PCA9538 8-bit GPIO expander
From: |
Titus Rwantare |
Subject: |
[PATCH 2/3] hw/gpio: add PCA9538 8-bit GPIO expander |
Date: |
Mon, 6 Feb 2023 19:49:35 +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 | 98 ++++++++++++++++++++++++++++++++++
include/hw/gpio/pca_i2c_gpio.h | 7 +++
2 files changed, 105 insertions(+)
diff --git a/hw/gpio/pca_i2c_gpio.c b/hw/gpio/pca_i2c_gpio.c
index afae497a22..f77d8d7e84 100644
--- a/hw/gpio/pca_i2c_gpio.c
+++ b/hw/gpio/pca_i2c_gpio.c
@@ -141,6 +141,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)
{
@@ -201,6 +236,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);
@@ -321,6 +397,23 @@ static void pca6416_gpio_class_init(ObjectClass *klass,
void *data)
pc->num_pins = PCA6416_NUM_PINS;
}
+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";
+ dc->realize = pca_i2c_realize;
+ dc->vmsd = &vmstate_pca_i2c_gpio;
+
+ k->event = pca_i2c_event;
+ k->recv = pca9538_recv;
+ k->send = pca9538_send;
+
+ pc->num_pins = PCA9538_NUM_PINS;
+}
+
static void pca_i2c_gpio_init(Object *obj)
{
PCAGPIOState *ps = PCA_I2C_GPIO(obj);
@@ -357,6 +450,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 a10897c0e0..8cd268e8f0 100644
--- a/include/hw/gpio/pca_i2c_gpio.h
+++ b/include/hw/gpio/pca_i2c_gpio.h
@@ -18,6 +18,7 @@
#include "qom/object.h"
#define PCA6416_NUM_PINS 16
+#define PCA9538_NUM_PINS 8
typedef struct PCAGPIOClass {
I2CSlaveClass parent;
@@ -61,6 +62,11 @@ 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 PCA6416_OUTPUT_DEFAULT 0xFFFF
#define PCA6416_CONFIG_DEFAULT 0xFFFF
@@ -68,5 +74,6 @@ OBJECT_DECLARE_TYPE(PCAGPIOState, PCAGPIOClass, PCA_I2C_GPIO)
#define PCA_I2C_CONFIG_DEFAULT 0xFFFF
#define TYPE_PCA6416_GPIO "pca6416"
+#define TYPE_PCA9538_GPIO "pca9538"
#endif
--
2.39.1.519.gcb327c4b5f-goog
- [PATCH 0/3] PCA I2C GPIO expanders, Titus Rwantare, 2023/02/06
- [PATCH 2/3] hw/gpio: add PCA9538 8-bit GPIO expander,
Titus Rwantare <=
- [PATCH 1/3] hw/gpio: add PCA6414 i2c GPIO expander, Titus Rwantare, 2023/02/06
- Re: [PATCH 1/3] hw/gpio: add PCA6414 i2c GPIO expander, Corey Minyard, 2023/02/06
- RE: [PATCH 1/3] hw/gpio: add PCA6414 i2c GPIO expander, Dong, Eddie, 2023/02/06
- Re: [PATCH 1/3] hw/gpio: add PCA6414 i2c GPIO expander, Joel Stanley, 2023/02/06