Commit 9cf28eed authored by Federico Vaga's avatar Federico Vaga

Merge branch '30-expose-sensor-output-via-linux-hwmon-api' into 'master'

Resolve "Implement hardware monitoring API"

See merge request be-cem-edl/fec/hardware-modules/fmc-adc-100m14b4cha!12
parents 6160f63b 71093c5e
......@@ -61,6 +61,7 @@ fmc-adc-100m14b4ch-y += fa-irq.o
fmc-adc-100m14b4ch-y += fa-debug.o
fmc-adc-100m14b4ch-y += fa-dma.o
fmc-adc-100m14b4ch-y += spi.o
fmc-adc-100m14b4ch-y += fa-hwmon.o
fmc-adc-100m14b4ch-spec-objs := fmc-adc-100m14b4ch-spec-core.o
fmc-adc-100m14b4ch-svec-objs := fmc-adc-100m14b4ch-svec-core.o
......@@ -167,12 +167,16 @@ void fa_calib_adc_config_chan(struct fa_dev *fa, unsigned int chan,
int range = fa->range[chan];
struct fa_calib_stanza *cal = &fa->calib.adc[range];
int gain;
int err;
if (fa_calib_is_compensation_on(fa)) {
int32_t delta_temp;
if (flags & FA_CALIB_FLAG_READ_TEMP)
temperature = fa_temperature_read(fa);
if (flags & FA_CALIB_FLAG_READ_TEMP) {
err = fa_temperature_read(fa, &temperature);
if(err)
temperature = 45000; /* 45.000 degrees as safe value */
}
delta_temp = (temperature / 10) - cal->temperature;
gain = fa_calib_adc_gain_fix(range, cal->gain[chan],
delta_temp);
......@@ -280,8 +284,11 @@ int fa_calib_dac_config_chan(struct fa_dev *fa, unsigned int chan,
if (fa_calib_is_compensation_on(fa)) {
int32_t delta_temp;
if (flags & FA_CALIB_FLAG_READ_TEMP)
temperature = fa_temperature_read(fa);
if (flags & FA_CALIB_FLAG_READ_TEMP) {
err = fa_temperature_read(fa, &temperature);
if(err)
temperature = 45000; /* 45.000 degrees as safe value */
}
delta_temp = (temperature / 10) - cal->temperature;
gain = fa_calib_dac_gain_fix(range, cal->gain[chan],
delta_temp);
......@@ -312,8 +319,11 @@ void fa_calib_config(struct fa_dev *fa)
{
int32_t temperature;
int i;
int err;
temperature = fa_temperature_read(fa);
err = fa_temperature_read(fa, &temperature);
if(err)
temperature = 45000; /* 45.000 degrees as safe value */
spin_lock(&fa->zdev->cset->lock);
for (i = 0; i < FA100M14B4C_NCHAN; ++i)
fa_calib_config_chan(fa, i, temperature, 0);
......
......@@ -126,19 +126,19 @@ bool fa_adc_is_output_randomizer(struct fa_dev *fa)
* DS18B20 returns units of 1/16 degree. We return units
* of 1/1000 of a degree instead.
*/
int32_t fa_temperature_read(struct fa_dev *fa)
int fa_temperature_read(struct fa_dev *fa, int32_t *temp)
{
uint32_t reg;
int16_t raw_temp;
reg = fa_ioread(fa, fa->fa_ow_base + 0x08);
if (reg & BIT(31)) {
dev_err(&fa->pdev->dev, "Temperature sensor failure\n");
return 45000; /* 45.000 degrees as save value */
return -EIO;
}
raw_temp = reg & 0xFFFF;
return (raw_temp * 1000UL + 8) / 16;
*temp = (int)((reg & 0xFFFF) * 1000UL + 8) / 16;
return 0;
}
/**
......@@ -880,6 +880,12 @@ int fa_probe(struct platform_device *pdev)
if (err < 0)
goto out_irq;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
err = fa_hwmon_init(fa);
if(err != 0)
dev_err(fa->msgdev, "Could not create HWMON device: %d", err);
#endif
return 0;
out_irq:
......
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2023 CERN (home.cern)
/*
* Author: Vaibhav Gupta <vaibhav.gupta@cern.ch>
*
* Hardware Monitoring for fa-dev
*/
#include <linux/hwmon.h>
#include "fmc-adc-100m14b4cha-private.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
static umode_t fa_hwmon_temp_is_visible(const void *_data,
enum hwmon_sensor_types type, u32 attr,
int channel)
{
return 0444;
}
static int fa_hwmon_temp_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int ret;
int32_t value;
struct fa_dev *fa = dev_get_drvdata(dev);
switch(attr) {
case hwmon_temp_min:
*val = 30*1000;
return 0;
case hwmon_temp_max:
*val = 60*1000;
return 0;
case hwmon_temp_crit:
*val = 65*1000;
return 0;
}
ret = fa_temperature_read(fa, &value);
if(ret < 0){
dev_err(dev, "Could not read temperature: %d", ret);
return ret;
}
*val = (long)value;
return 0;
}
static int fa_hwmon_temp_sensor_id_read(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
struct fa_dev *fa = dev_get_drvdata(dev);
*str = fa->hwmon_temp_sensor_id;
return 0;
}
static const struct hwmon_channel_info *fa_hwmon_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MIN |
HWMON_T_MAX | HWMON_T_CRIT),
NULL
};
static const struct hwmon_ops fa_hwmon_temp_ops = {
.is_visible = fa_hwmon_temp_is_visible,
.read = fa_hwmon_temp_read,
.read_string = fa_hwmon_temp_sensor_id_read
};
static const struct hwmon_chip_info fa_hwmon_temp_chip_info = {
.ops = &fa_hwmon_temp_ops,
.info = fa_hwmon_info,
};
int fa_hwmon_init(struct fa_dev *fa)
{
struct device *dev = &fa->pdev->dev;
fa->hwmon_dev = devm_hwmon_device_register_with_info(dev,
"FMC_ADC_100M14B4C",
fa,
&fa_hwmon_temp_chip_info,
NULL);
if(!IS_ERR(fa->hwmon_dev)) {
fa->hwmon_temp_sensor_id = devm_kasprintf(fa->hwmon_dev,
GFP_KERNEL,
"Temperature [%s]",
dev_name(&fa->slot->dev));
if(!fa->hwmon_temp_sensor_id) {
devm_hwmon_device_unregister(dev);
return -ENOMEM;
}
return 0;
}
return PTR_ERR(fa->hwmon_dev);
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) */
......@@ -335,6 +335,7 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
struct fa_dev *fa = get_zfadc(dev);
void *baseoff = fa->fa_adc_csr_base;
int i, reg_index;
int err, temp;
i = FA100M14B4C_NCHAN;
......@@ -370,7 +371,10 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
/* ZIO automatically return the attribute value */
return 0;
case ZFA_SW_R_NOADDRES_TEMP:
*usr_val = fa_temperature_read(fa);
err = fa_temperature_read(fa, &temp);
if(err)
return err;
*usr_val = (uint32_t)temp;
return 0;
case ZFA_SW_CH1_OFFSET_ZERO:
i--;
......
......@@ -345,7 +345,10 @@ struct fa_dev {
/* one-wire */
uint8_t ds18_id[8];
unsigned long next_t;
int temp; /* temperature: scaled by 4 bits */
/* HWMON */
char *hwmon_temp_sensor_id;
struct device *hwmon_dev;
/* Calibration Data */
struct fa_calib calib;
......@@ -504,7 +507,7 @@ extern const struct zfa_field_desc zfad_regs[];
/* Functions exported by fa-core.c */
extern int zfad_fsm_command(struct fa_dev *fa, uint32_t command);
extern int zfad_convert_hw_range(uint32_t bitmask);
extern int32_t fa_temperature_read(struct fa_dev *fa);
extern int fa_temperature_read(struct fa_dev *fa, int *temp);
extern int fa_trigger_software(struct fa_dev *fa);
extern int fa_fsm_wait_state(struct fa_dev *fa,
enum fa100m14b4c_fsm_state state,
......@@ -567,4 +570,8 @@ extern void fa_calib_config_chan(struct fa_dev *fa, unsigned int chan,
extern int fa_debug_init(struct fa_dev *fa);
extern void fa_debug_exit(struct fa_dev *fa);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
extern int fa_hwmon_init(struct fa_dev *fa);
#endif
#endif /* FMC_ADC_H_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment