baylibre-acme: Add support for probe factor setting.
Implement support for SR_CONF_PROBE_FACTOR setting in BayLibre ACME driver. Given the channel-group parameter this allows to set the shunt resistance for each probe. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
parent
d3c81725ae
commit
61f2b7f74c
|
@ -27,6 +27,7 @@ static const uint32_t devopts[] = {
|
||||||
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
SR_CONF_LIMIT_MSEC | SR_CONF_GET | SR_CONF_SET,
|
||||||
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST,
|
||||||
|
SR_CONF_PROBE_FACTOR | SR_CONF_GET | SR_CONF_SET,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_SAMPLE_RATE 500 /* In Hz */
|
#define MAX_SAMPLE_RATE 500 /* In Hz */
|
||||||
|
@ -168,8 +169,7 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
{
|
{
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
int ret;
|
int ret;
|
||||||
|
uint64_t shunt;
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
|
@ -184,6 +184,13 @@ static int config_get(uint32_t key, GVariant **data,
|
||||||
case SR_CONF_SAMPLERATE:
|
case SR_CONF_SAMPLERATE:
|
||||||
*data = g_variant_new_uint64(devc->samplerate);
|
*data = g_variant_new_uint64(devc->samplerate);
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_PROBE_FACTOR:
|
||||||
|
if (!cg)
|
||||||
|
return SR_ERR_CHANNEL_GROUP;
|
||||||
|
ret = bl_acme_get_shunt(cg, &shunt);
|
||||||
|
if (ret == SR_OK)
|
||||||
|
*data = g_variant_new_uint64(shunt);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
@ -199,8 +206,6 @@ static int config_set(uint32_t key, GVariant *data,
|
||||||
uint64_t samplerate;
|
uint64_t samplerate;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
(void)cg;
|
|
||||||
|
|
||||||
if (sdi->status != SR_ST_ACTIVE)
|
if (sdi->status != SR_ST_ACTIVE)
|
||||||
return SR_ERR_DEV_CLOSED;
|
return SR_ERR_DEV_CLOSED;
|
||||||
|
|
||||||
|
@ -229,6 +234,11 @@ static int config_set(uint32_t key, GVariant *data,
|
||||||
devc->samplerate = samplerate;
|
devc->samplerate = samplerate;
|
||||||
sr_dbg("Setting samplerate to %" PRIu64, devc->samplerate);
|
sr_dbg("Setting samplerate to %" PRIu64, devc->samplerate);
|
||||||
break;
|
break;
|
||||||
|
case SR_CONF_PROBE_FACTOR:
|
||||||
|
if (!cg)
|
||||||
|
return SR_ERR_CHANNEL_GROUP;
|
||||||
|
ret = bl_acme_set_shunt(cg, g_variant_get_uint64(data));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = SR_ERR_NA;
|
ret = SR_ERR_NA;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,12 @@
|
||||||
#include <stdlib.h> /* strtol() */
|
#include <stdlib.h> /* strtol() */
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h> /* open(), etc... */
|
#include <fcntl.h> /* open(), etc... */
|
||||||
|
#include <glib/gstdio.h>
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
|
||||||
struct channel_group_priv {
|
struct channel_group_priv {
|
||||||
int hwmon_num;
|
int hwmon_num;
|
||||||
|
int probe_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct channel_priv {
|
struct channel_priv {
|
||||||
|
@ -40,6 +42,9 @@ static const uint8_t temp_i2c_addrs[] = {
|
||||||
0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x4f, 0x4b,
|
0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x4f, 0x4b,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MOHM_TO_UOHM(x) ((x) * 1000)
|
||||||
|
#define UOHM_TO_MOHM(x) ((x) / 1000)
|
||||||
|
|
||||||
SR_PRIV uint8_t bl_acme_get_enrg_addr(int index)
|
SR_PRIV uint8_t bl_acme_get_enrg_addr(int index)
|
||||||
{
|
{
|
||||||
return enrg_i2c_addrs[index];
|
return enrg_i2c_addrs[index];
|
||||||
|
@ -212,6 +217,7 @@ SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
|
||||||
cg = g_malloc0(sizeof(struct sr_channel_group));
|
cg = g_malloc0(sizeof(struct sr_channel_group));
|
||||||
cgp = g_malloc0(sizeof(struct channel_group_priv));
|
cgp = g_malloc0(sizeof(struct channel_group_priv));
|
||||||
cgp->hwmon_num = hwmon;
|
cgp->hwmon_num = hwmon;
|
||||||
|
cgp->probe_type = type;
|
||||||
cg->name = g_strdup_printf("Probe_%d", prb_num);
|
cg->name = g_strdup_printf("Probe_%d", prb_num);
|
||||||
cg->priv = cgp;
|
cg->priv = cgp;
|
||||||
|
|
||||||
|
@ -231,6 +237,108 @@ SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets path to the hwmon attribute if this channel group
|
||||||
|
* supports shunt resistance setting. The caller has to supply
|
||||||
|
* a valid GString.
|
||||||
|
*/
|
||||||
|
static int get_shunt_path(const struct sr_channel_group *cg, GString *path)
|
||||||
|
{
|
||||||
|
struct channel_group_priv *cgp;
|
||||||
|
int ret = SR_OK, status;
|
||||||
|
|
||||||
|
cgp = cg->priv;
|
||||||
|
|
||||||
|
if (cgp->probe_type != PROBE_ENRG) {
|
||||||
|
sr_err("Probe doesn't support shunt resistance setting");
|
||||||
|
return SR_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf(path,
|
||||||
|
"/sys/class/hwmon/hwmon%d/shunt_resistor",
|
||||||
|
cgp->hwmon_num);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The shunt_resistor sysfs attribute is available
|
||||||
|
* in the Linux kernel since version 3.20. We have
|
||||||
|
* to notify the user if this attribute is not
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
status = g_file_test(path->str, G_FILE_TEST_EXISTS);
|
||||||
|
if (!status) {
|
||||||
|
sr_err("shunt_resistance attribute not present please update "
|
||||||
|
"your kernel to version >=3.20");
|
||||||
|
return SR_ERR_NA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int bl_acme_get_shunt(const struct sr_channel_group *cg,
|
||||||
|
uint64_t *shunt)
|
||||||
|
{
|
||||||
|
GString *path = g_string_sized_new(64);
|
||||||
|
gchar *contents;
|
||||||
|
int status, ret = SR_OK;
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
status = get_shunt_path(cg, path);
|
||||||
|
if (status != SR_OK) {
|
||||||
|
ret = status;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = g_file_get_contents(path->str, &contents, NULL, &err);
|
||||||
|
if (!status) {
|
||||||
|
sr_err("Error reading shunt resistance: %s", err->message);
|
||||||
|
ret = SR_ERR_IO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*shunt = UOHM_TO_MOHM(strtol(contents, NULL, 10));
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_string_free(path, TRUE);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SR_PRIV int bl_acme_set_shunt(const struct sr_channel_group *cg,
|
||||||
|
uint64_t shunt)
|
||||||
|
{
|
||||||
|
GString *path = g_string_sized_new(64);;
|
||||||
|
int status, ret = SR_OK;
|
||||||
|
FILE *fd;
|
||||||
|
|
||||||
|
status = get_shunt_path(cg, path);
|
||||||
|
if (status != SR_OK) {
|
||||||
|
ret = status;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't use g_file_set_contents() here, as it calls open() with
|
||||||
|
* O_EXEC flag in a sysfs directory thus failing with EACCES.
|
||||||
|
*/
|
||||||
|
fd = g_fopen(path->str, "w");
|
||||||
|
if (!fd) {
|
||||||
|
sr_err("Error opening %s: %s", path->str, strerror(errno));
|
||||||
|
g_string_free(path, TRUE);
|
||||||
|
return SR_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_free(path, TRUE);
|
||||||
|
g_fprintf(fd, "%llu\n", MOHM_TO_UOHM(shunt));
|
||||||
|
/*
|
||||||
|
* XXX There's no g_fclose() in GLib. This seems to work,
|
||||||
|
* but is it safe?
|
||||||
|
*/
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_string_free(path, TRUE);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int channel_to_mq(struct sr_channel *ch)
|
static int channel_to_mq(struct sr_channel *ch)
|
||||||
{
|
{
|
||||||
struct channel_priv *chp;
|
struct channel_priv *chp;
|
||||||
|
|
|
@ -81,6 +81,11 @@ SR_PRIV gboolean bl_acme_detect_probe(unsigned int addr,
|
||||||
SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
|
SR_PRIV gboolean bl_acme_register_probe(struct sr_dev_inst *sdi, int type,
|
||||||
unsigned int addr, int prb_num);
|
unsigned int addr, int prb_num);
|
||||||
|
|
||||||
|
SR_PRIV int bl_acme_get_shunt(const struct sr_channel_group *cg,
|
||||||
|
uint64_t *shunt);
|
||||||
|
SR_PRIV int bl_acme_set_shunt(const struct sr_channel_group *cg,
|
||||||
|
uint64_t shunt);
|
||||||
|
|
||||||
SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data);
|
SR_PRIV int bl_acme_receive_data(int fd, int revents, void *cb_data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue