mirror of https://gitee.com/openkylin/qemu.git
hw/misc/pca9552: Add generic PCA955xClass, parent of TYPE_PCA9552
Extract the code common to the PCA955x family in PCA955xClass,
keeping the PCA9552 specific parts into pca9552_class_init().
Remove the 'TODO' comment added in commit 5141d4158c
.
Suggested-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Tested-by: Cédric Le Goater <clg@kaod.org>
Message-id: 20200623072723.6324-5-f4bug@amsat.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
ec17228a25
commit
736132e455
|
@ -4,6 +4,7 @@
|
|||
* https://www.nxp.com/docs/en/application-note/AN264.pdf
|
||||
*
|
||||
* Copyright (c) 2017-2018, IBM Corporation.
|
||||
* Copyright (c) 2020 Philippe Mathieu-Daudé
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
|
@ -18,6 +19,20 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
|
||||
typedef struct PCA955xClass {
|
||||
/*< private >*/
|
||||
I2CSlaveClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
uint8_t pin_count;
|
||||
uint8_t max_reg;
|
||||
} PCA955xClass;
|
||||
|
||||
#define PCA955X_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PCA955xClass, (klass), TYPE_PCA955X)
|
||||
#define PCA955X_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(PCA955xClass, (obj), TYPE_PCA955X)
|
||||
|
||||
#define PCA9552_LED_ON 0x0
|
||||
#define PCA9552_LED_OFF 0x1
|
||||
#define PCA9552_LED_PWM0 0x2
|
||||
|
@ -35,9 +50,10 @@ static uint8_t pca955x_pin_get_config(PCA955xState *s, int pin)
|
|||
|
||||
static void pca955x_update_pin_input(PCA955xState *s)
|
||||
{
|
||||
PCA955xClass *k = PCA955X_GET_CLASS(s);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->pin_count; i++) {
|
||||
for (i = 0; i < k->pin_count; i++) {
|
||||
uint8_t input_reg = PCA9552_INPUT0 + (i / 8);
|
||||
uint8_t input_shift = (i % 8);
|
||||
uint8_t config = pca955x_pin_get_config(s, i);
|
||||
|
@ -112,10 +128,12 @@ static void pca955x_write(PCA955xState *s, uint8_t reg, uint8_t data)
|
|||
*/
|
||||
static void pca955x_autoinc(PCA955xState *s)
|
||||
{
|
||||
PCA955xClass *k = PCA955X_GET_CLASS(s);
|
||||
|
||||
if (s->pointer != 0xFF && s->pointer & PCA9552_AUTOINC) {
|
||||
uint8_t reg = s->pointer & 0xf;
|
||||
|
||||
reg = (reg + 1) % (s->max_reg + 1);
|
||||
reg = (reg + 1) % (k->max_reg + 1);
|
||||
s->pointer = reg | PCA9552_AUTOINC;
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +194,7 @@ static int pca955x_event(I2CSlave *i2c, enum i2c_event event)
|
|||
static void pca955x_get_led(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
PCA955xClass *k = PCA955X_GET_CLASS(obj);
|
||||
PCA955xState *s = PCA955X(obj);
|
||||
int led, rc, reg;
|
||||
uint8_t state;
|
||||
|
@ -185,7 +204,7 @@ static void pca955x_get_led(Object *obj, Visitor *v, const char *name,
|
|||
error_setg(errp, "%s: error reading %s", __func__, name);
|
||||
return;
|
||||
}
|
||||
if (led < 0 || led > s->pin_count) {
|
||||
if (led < 0 || led > k->pin_count) {
|
||||
error_setg(errp, "%s invalid led %s", __func__, name);
|
||||
return;
|
||||
}
|
||||
|
@ -212,6 +231,7 @@ static inline uint8_t pca955x_ledsel(uint8_t oldval, int led_num, int state)
|
|||
static void pca955x_set_led(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
PCA955xClass *k = PCA955X_GET_CLASS(obj);
|
||||
PCA955xState *s = PCA955X(obj);
|
||||
Error *local_err = NULL;
|
||||
int led, rc, reg, val;
|
||||
|
@ -228,7 +248,7 @@ static void pca955x_set_led(Object *obj, Visitor *v, const char *name,
|
|||
error_setg(errp, "%s: error reading %s", __func__, name);
|
||||
return;
|
||||
}
|
||||
if (led < 0 || led > s->pin_count) {
|
||||
if (led < 0 || led > k->pin_count) {
|
||||
error_setg(errp, "%s invalid led %s", __func__, name);
|
||||
return;
|
||||
}
|
||||
|
@ -283,17 +303,11 @@ static void pca9552_reset(DeviceState *dev)
|
|||
|
||||
static void pca955x_initfn(Object *obj)
|
||||
{
|
||||
PCA955xState *s = PCA955X(obj);
|
||||
PCA955xClass *k = PCA955X_GET_CLASS(obj);
|
||||
int led;
|
||||
|
||||
/* If support for the other PCA955X devices are implemented, these
|
||||
* constant values might be part of class structure describing the
|
||||
* PCA955X device
|
||||
*/
|
||||
s->max_reg = PCA9552_LS3;
|
||||
s->pin_count = 16;
|
||||
|
||||
for (led = 0; led < s->pin_count; led++) {
|
||||
assert(k->pin_count <= PCA955X_PIN_COUNT_MAX);
|
||||
for (led = 0; led < k->pin_count; led++) {
|
||||
char *name;
|
||||
|
||||
name = g_strdup_printf("led%d", led);
|
||||
|
@ -303,28 +317,44 @@ static void pca955x_initfn(Object *obj)
|
|||
}
|
||||
}
|
||||
|
||||
static void pca9552_class_init(ObjectClass *klass, void *data)
|
||||
static void pca955x_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
|
||||
|
||||
k->event = pca955x_event;
|
||||
k->recv = pca955x_recv;
|
||||
k->send = pca955x_send;
|
||||
}
|
||||
|
||||
static const TypeInfo pca955x_info = {
|
||||
.name = TYPE_PCA955X,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_init = pca955x_initfn,
|
||||
.instance_size = sizeof(PCA955xState),
|
||||
.class_init = pca955x_class_init,
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void pca9552_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PCA955xClass *pc = PCA955X_CLASS(oc);
|
||||
|
||||
dc->reset = pca9552_reset;
|
||||
dc->vmsd = &pca9552_vmstate;
|
||||
pc->max_reg = PCA9552_LS3;
|
||||
pc->pin_count = 16;
|
||||
}
|
||||
|
||||
static const TypeInfo pca9552_info = {
|
||||
.name = TYPE_PCA9552,
|
||||
.parent = TYPE_I2C_SLAVE,
|
||||
.instance_init = pca955x_initfn,
|
||||
.instance_size = sizeof(PCA955xState),
|
||||
.parent = TYPE_PCA955X,
|
||||
.class_init = pca9552_class_init,
|
||||
};
|
||||
|
||||
static void pca955x_register_types(void)
|
||||
{
|
||||
type_register_static(&pca955x_info);
|
||||
type_register_static(&pca9552_info);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,11 @@
|
|||
#include "hw/i2c/i2c.h"
|
||||
|
||||
#define TYPE_PCA9552 "pca9552"
|
||||
#define PCA955X(obj) OBJECT_CHECK(PCA955xState, (obj), TYPE_PCA9552)
|
||||
#define TYPE_PCA955X "pca955x"
|
||||
#define PCA955X(obj) OBJECT_CHECK(PCA955xState, (obj), TYPE_PCA955X)
|
||||
|
||||
#define PCA955X_NR_REGS 10
|
||||
#define PCA955X_PIN_COUNT_MAX 16
|
||||
|
||||
typedef struct PCA955xState {
|
||||
/*< private >*/
|
||||
|
@ -25,8 +27,6 @@ typedef struct PCA955xState {
|
|||
uint8_t pointer;
|
||||
|
||||
uint8_t regs[PCA955X_NR_REGS];
|
||||
uint8_t max_reg;
|
||||
uint8_t pin_count;
|
||||
} PCA955xState;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue