All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Philippe Mathieu-Daudé" <f4bug@amsat.org>
To: John Wang <wangzhiqiang.bj@bytedance.com>,
	clg@kaod.org, xuxiaohan@bytednace.com, yulei.sh@bytedance.com,
	joel@jms.id.au
Cc: Peter Maydell <peter.maydell@linaro.org>,
	"open list:ARM TCG CPUs" <qemu-arm@nongnu.org>,
	"open list:All patches CC here" <qemu-devel@nongnu.org>
Subject: Re: [PATCH v2 1/2] hw/misc: add an EMC141{3,4} device model
Date: Sat, 24 Oct 2020 19:32:05 +0200	[thread overview]
Message-ID: <d1555d4d-88b3-8dfa-4871-5109fe524275@amsat.org> (raw)
In-Reply-To: <20201008090244.3770-1-wangzhiqiang.bj@bytedance.com>

Hi John,

On 10/8/20 11:02 AM, John Wang wrote:
> Largely inspired by the TMP421 temperature sensor, here is a model for
> the EMC1413 temperature sensors.

"EMC1413/EMC1414" as you aim to model both.

> 
> Specs can be found here :
>    https://pdf1.alldatasheet.com/datasheet-pdf/view/533713/SMSC/EMC1413.html

Please update to:

Datasheet "Microchip EMC1413/EMC1414 DS20005274A" available here:
http://ww1.microchip.com/downloads/en/DeviceDoc/20005274A.pdf

> 
> Signed-off-by: John Wang <wangzhiqiang.bj@bytedance.com>
> ---
> v2:
>    - Remove DeviceInfo
>    - commit message: TMP423 -> TMP421
> ---
>   hw/arm/Kconfig      |   1 +
>   hw/misc/Kconfig     |   4 +
>   hw/misc/emc1413.c   | 305 ++++++++++++++++++++++++++++++++++++++++++++
>   hw/misc/meson.build |   1 +
>   4 files changed, 311 insertions(+)
>   create mode 100644 hw/misc/emc1413.c
> 
> diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
> index f303c6bead..8801ada145 100644
> --- a/hw/arm/Kconfig
> +++ b/hw/arm/Kconfig
> @@ -402,6 +402,7 @@ config ASPEED_SOC
>       select SSI_M25P80
>       select TMP105
>       select TMP421
> +    select EMC1413
>       select UNIMP
>   
>   config MPS2
> diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
> index 3185456110..91badf2d4d 100644
> --- a/hw/misc/Kconfig
> +++ b/hw/misc/Kconfig
> @@ -13,6 +13,10 @@ config TMP421
>       bool
>       depends on I2C
>   
> +config EMC1413
> +    bool
> +    depends on I2C
> +
>   config ISA_DEBUG
>       bool
>       depends on ISA_BUS
> diff --git a/hw/misc/emc1413.c b/hw/misc/emc1413.c

Can you rename it emc141x.c please?

> new file mode 100644
> index 0000000000..160a59495a
> --- /dev/null
> +++ b/hw/misc/emc1413.c
> @@ -0,0 +1,305 @@
> +/*
> + * SMSC EMC141X temperature sensor.
> + *
> + * Copyright (c) 2020 Bytedance Corporation
> + * Written by John Wang <wangzhiqiang.bj@bytedance.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 or
> + * (at your option) version 3 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/i2c/i2c.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "qemu/module.h"
> +#include "qom/object.h"
> +
> +#define DEVICE_ID_REG                    0xfd
> +#define MANUFACTURER_ID_REG              0xfe
> +#define REVISION_REG                     0xff

> +#define EMC1413_DEVICE_ID                0x21
> +#define EMC1414_DEVICE_ID                0x25
> +

Please add ...:

#define SENSORS_COUNT_MAX 4

> +struct EMC141XState {
> +    I2CSlave i2c;
> +    uint8_t temperature[4];
> +    uint8_t min[4];
> +    uint8_t max[4];

... and use it here (alternatively you can use the .heap).

> +    uint8_t len;
> +    uint8_t data;
> +    uint8_t pointer;
> +};
> +
> +struct EMC141XClass {
> +    I2CSlaveClass parent_class;
> +    uint8_t model;

Please add here ...:

        unsigned sensors_count;

... which is 1+2 for the EMC1413 and 1+3 for the EMC1414.

> +};
> +
> +#define TYPE_EMC141X "emc141x"
> +OBJECT_DECLARE_TYPE(EMC141XState, EMC141XClass, EMC141X)
> +
> +
> +/* the EMC141X registers */
> +#define EMC141X_TEMP_HIGH0               0x00
> +#define EMC141X_TEMP_HIGH1               0x01
> +#define EMC141X_TEMP_HIGH2               0x23
> +#define EMC141X_TEMP_HIGH3               0x2a
> +#define EMC141X_TEMP_MAX_HIGH0           0x05
> +#define EMC141X_TEMP_MIN_HIGH0           0x06
> +#define EMC141X_TEMP_MAX_HIGH1           0x07
> +#define EMC141X_TEMP_MIN_HIGH1           0x08
> +#define EMC141X_TEMP_MAX_HIGH2           0x15
> +#define EMC141X_TEMP_MIN_HIGH2           0x16
> +#define EMC141X_TEMP_MAX_HIGH3           0x2c
> +#define EMC141X_TEMP_MIN_HIGH3           0x2d
> +
> +static void emc141x_get_temperature(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
> +{
> +    EMC141XState *s = EMC141X(obj);

        EMC141XClass *sc = ...

> +    int64_t value;
> +    int tempid;
> +
> +    if (sscanf(name, "temperature%d", &tempid) != 1) {
> +        error_setg(errp, "error reading %s: %s", name, g_strerror(errno));
> +        return;
> +    }
> +
> +    if (tempid >= 4 || tempid < 0) {

You have to check sc->sensors_count.

> +        error_setg(errp, "error reading %s", name);
> +        return;
> +    }
> +
> +    value = s->temperature[tempid] * 1000;
> +
> +    visit_type_int(v, name, &value, errp);
> +}
> +
> +static void emc141x_set_temperature(Object *obj, Visitor *v, const char *name,
> +                                   void *opaque, Error **errp)
> +{
> +    EMC141XState *s = EMC141X(obj);
> +    int64_t temp;
> +    int tempid;
> +
> +    if (!visit_type_int(v, name, &temp, errp)) {
> +        return;
> +    }
> +
> +    if (sscanf(name, "temperature%d", &tempid) != 1) {
> +        error_setg(errp, "error reading %s: %s", name, g_strerror(errno));
> +        return;
> +    }
> +
> +    if (tempid >= 4 || tempid < 0) {
> +        error_setg(errp, "error reading %s", name);
> +        return;
> +    }
> +
> +    s->temperature[tempid] = temp / 1000;
> +}
> +
> +struct emc141x_reg {
> +    uint8_t addr;
> +    uint8_t *data;
> +};
> +
> +static void emc141x_read(EMC141XState *s)
> +{
> +    EMC141XClass *sc = EMC141X_GET_CLASS(s);
> +    uint8_t smsc_manufacturer_id = 0x5d;
> +    uint8_t revision = 0x04;
> +    struct emc141x_reg emc141x_regs[] = {
> +        {DEVICE_ID_REG, &sc->model},
> +        {MANUFACTURER_ID_REG, &smsc_manufacturer_id},
> +        {REVISION_REG, &revision},
> +        {EMC141X_TEMP_HIGH0, &s->temperature[0]},
> +        {EMC141X_TEMP_HIGH1, &s->temperature[1]},
> +        {EMC141X_TEMP_HIGH2, &s->temperature[2]},
> +        {EMC141X_TEMP_HIGH3, &s->temperature[3]},
> +        {EMC141X_TEMP_MAX_HIGH0, &s->max[0]},
> +        {EMC141X_TEMP_MAX_HIGH1, &s->max[1]},
> +        {EMC141X_TEMP_MAX_HIGH2, &s->max[2]},
> +        {EMC141X_TEMP_MAX_HIGH3, &s->max[3]},
> +        {EMC141X_TEMP_MIN_HIGH0, &s->min[0]},
> +        {EMC141X_TEMP_MIN_HIGH1, &s->min[1]},
> +        {EMC141X_TEMP_MIN_HIGH2, &s->min[2]},
> +        {EMC141X_TEMP_MIN_HIGH3, &s->min[3]},
> +    };
> +    size_t i;
> +    for (i = 0; i < ARRAY_SIZE(emc141x_regs); i++) {
> +        if (emc141x_regs[i].addr == s->pointer) {
> +            s->data = *(emc141x_regs[i].data);

This function seems over complex... So bug prone.

tmp421_read() is easier to review.

> +            return;
> +        }
> +    }
> +}
> +
> +static void emc141x_write(EMC141XState *s)
> +{
> +    struct emc141x_reg emc141x_regs[] = {
> +        {EMC141X_TEMP_MAX_HIGH0, &s->max[0]},
> +        {EMC141X_TEMP_MAX_HIGH1, &s->max[1]},
> +        {EMC141X_TEMP_MAX_HIGH2, &s->max[2]},
> +        {EMC141X_TEMP_MAX_HIGH3, &s->max[3]},
> +        {EMC141X_TEMP_MIN_HIGH0, &s->min[0]},
> +        {EMC141X_TEMP_MIN_HIGH1, &s->min[1]},
> +        {EMC141X_TEMP_MIN_HIGH2, &s->min[2]},
> +        {EMC141X_TEMP_MIN_HIGH3, &s->min[3]},
> +    };
> +    size_t i;
> +    for (i = 0; i < ARRAY_SIZE(emc141x_regs); i++) {
> +        if (emc141x_regs[i].addr == s->pointer) {
> +            *(emc141x_regs[i].data) = s->data;

Ditto.

> +            return;
> +        }
> +    }
> +}
> +
> +static uint8_t emc141x_rx(I2CSlave *i2c)
> +{
> +    EMC141XState *s = EMC141X(i2c);
> +
> +    if (s->len == 0) {
> +        s->len++;
> +        return s->data;
> +    } else {
> +        return 0xff;
> +    }
> +}
> +
> +static int emc141x_tx(I2CSlave *i2c, uint8_t data)
> +{
> +    EMC141XState *s = EMC141X(i2c);
> +
> +    if (s->len == 0) {
> +        /* first byte is the reg pointer */
> +        s->pointer = data;
> +        s->len++;
> +    } else if (s->len == 1) {
> +        s->data = data;
> +        emc141x_write(s);
> +    }
> +
> +    return 0;
> +}
> +
> +static int emc141x_event(I2CSlave *i2c, enum i2c_event event)
> +{
> +    EMC141XState *s = EMC141X(i2c);
> +
> +    if (event == I2C_START_RECV) {
> +        emc141x_read(s);
> +    }
> +
> +    s->len = 0;
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_emc141x = {
> +    .name = "EMC141X",
> +    .version_id = 0,
> +    .minimum_version_id = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT8(len, EMC141XState),
> +        VMSTATE_UINT8(data, EMC141XState),
> +        VMSTATE_UINT8(pointer, EMC141XState),
> +        VMSTATE_UINT8_ARRAY(temperature, EMC141XState, 4),
> +        VMSTATE_UINT8_ARRAY(min, EMC141XState, 4),
> +        VMSTATE_UINT8_ARRAY(max, EMC141XState, 4),
> +        VMSTATE_I2C_SLAVE(i2c, EMC141XState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void emc141x_reset(I2CSlave *i2c)
> +{
> +    EMC141XState *s = EMC141X(i2c);
> +
> +    memset(s->temperature, 0, sizeof(s->temperature));
> +    memset(s->min, 0, sizeof(s->min));
> +    memset(s->max, 0x55, sizeof(s->max));
> +    s->pointer = 0;
> +    s->len = 0;
> +}
> +
> +static void emc141x_realize(DeviceState *dev, Error **errp)
> +{
> +    EMC141XState *s = EMC141X(dev);
> +
> +    emc141x_reset(&s->i2c);
> +}
> +
> +static void emc141x_initfn(Object *obj)
> +{
> +    object_property_add(obj, "temperature0", "int",
> +                        emc141x_get_temperature,
> +                        emc141x_set_temperature, NULL, NULL);
> +    object_property_add(obj, "temperature1", "int",
> +                        emc141x_get_temperature,
> +                        emc141x_set_temperature, NULL, NULL);
> +    object_property_add(obj, "temperature2", "int",
> +                        emc141x_get_temperature,
> +                        emc141x_set_temperature, NULL, NULL);
> +    object_property_add(obj, "temperature3", "int",
> +                        emc141x_get_temperature,
> +                        emc141x_set_temperature, NULL, NULL);
> +}
> +
> +static void emc141x_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
> +    EMC141XClass *sc = EMC141X_CLASS(klass);
> +
> +    dc->realize = emc141x_realize;

This handler does not realize anything, so please change
to dc->reset instead.

> +    k->event = emc141x_event;
> +    k->recv = emc141x_rx;
> +    k->send = emc141x_tx;
> +    dc->vmsd = &vmstate_emc141x;
> +    sc->model = (uintptr_t)data;
> +}
> +
> +static const TypeInfo emc141x_info = {
> +    .name          = TYPE_EMC141X,
> +    .parent        = TYPE_I2C_SLAVE,
> +    .instance_size = sizeof(EMC141XState),
> +    .class_size    = sizeof(EMC141XClass),
> +    .instance_init = emc141x_initfn,
> +    .abstract      = true,
> +};
> +
> +static const TypeInfo emc1413_info = {
> +    .name          = "emc1413",
> +    .parent        = TYPE_EMC141X,
> +    .class_init    = emc141x_class_init,

Please add emc1413_class_init() with

  ec->model = EMC1413_DEVICE_ID;
  ec->sensors_count = 3;


> +    .class_data    = (void *)EMC1413_DEVICE_ID,
> +};
> +
> +static const TypeInfo emc1414_info = {
> +    .name          = "emc1414",
> +    .parent        = TYPE_EMC141X,
> +    .class_init    = emc141x_class_init,

Please add emc1414_class_init():

  ec->model = EMC1414_DEVICE_ID;
  ec->sensors_count = 4;

> +    .class_data    = (void *)EMC1414_DEVICE_ID,
> +};
> +
> +static void emc141x_register_types(void)
> +{
> +    type_register_static(&emc141x_info);
> +    type_register_static(&emc1413_info);
> +    type_register_static(&emc1414_info);
> +}
> +
> +type_init(emc141x_register_types)
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 793d45b1dc..08821c72ba 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -9,6 +9,7 @@ softmmu_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c'))
>   softmmu_ss.add(when: 'CONFIG_SGA', if_true: files('sga.c'))
>   softmmu_ss.add(when: 'CONFIG_TMP105', if_true: files('tmp105.c'))
>   softmmu_ss.add(when: 'CONFIG_TMP421', if_true: files('tmp421.c'))
> +softmmu_ss.add(when: 'CONFIG_EMC1413', if_true: files('emc1413.c'))

I'd use CONFIG_EMC141X.

>   softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
>   softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
>   
> 



      parent reply	other threads:[~2020-10-24 17:33 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-08  9:02 [PATCH v2 1/2] hw/misc: add an EMC141{3,4} device model John Wang
2020-10-08  9:02 ` [PATCH v2 2/2] aspeed: Add support for the g220a-bmc board John Wang
2020-10-08 17:19 ` [PATCH v2 1/2] hw/misc: add an EMC141{3,4} device model Cédric Le Goater
2020-10-24  9:25   ` [External] Re: [PATCH v2 1/2] hw/misc: add an EMC141{3, 4} " John Wang
2020-10-24 17:33   ` [PATCH v2 1/2] hw/misc: add an EMC141{3,4} " Philippe Mathieu-Daudé
2020-10-24 17:32 ` Philippe Mathieu-Daudé [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d1555d4d-88b3-8dfa-4871-5109fe524275@amsat.org \
    --to=f4bug@amsat.org \
    --cc=clg@kaod.org \
    --cc=joel@jms.id.au \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=wangzhiqiang.bj@bytedance.com \
    --cc=xuxiaohan@bytednace.com \
    --cc=yulei.sh@bytedance.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.