in nct7904.c [1012:1161]
static int nct7904_probe(struct i2c_client *client)
{
struct nct7904_data *data;
struct device *hwmon_dev;
struct device *dev = &client->dev;
int ret, i;
u32 mask;
u8 val, bit;
data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
mutex_init(&data->bank_lock);
data->bank_sel = -1;
/* Setup sensor groups. */
/* FANIN attributes */
ret = nct7904_read_reg16(data, BANK_0, FANIN_CTRL0_REG);
if (ret < 0)
return ret;
data->fanin_mask = (ret >> 8) | ((ret & 0xff) << 8);
/*
* VSEN attributes
*
* Note: voltage sensors overlap with external temperature
* sensors. So, if we ever decide to support the latter
* we will have to adjust 'vsen_mask' accordingly.
*/
mask = 0;
ret = nct7904_read_reg16(data, BANK_0, VT_ADC_CTRL0_REG);
if (ret >= 0)
mask = (ret >> 8) | ((ret & 0xff) << 8);
ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
if (ret >= 0)
mask |= (ret << 16);
data->vsen_mask = mask;
/* CPU_TEMP attributes */
ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL0_REG);
if (ret < 0)
return ret;
if ((ret & 0x6) == 0x6)
data->tcpu_mask |= 1; /* TR1 */
if ((ret & 0x18) == 0x18)
data->tcpu_mask |= 2; /* TR2 */
if ((ret & 0x20) == 0x20)
data->tcpu_mask |= 4; /* TR3 */
if ((ret & 0x80) == 0x80)
data->tcpu_mask |= 8; /* TR4 */
/* LTD */
ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG);
if (ret < 0)
return ret;
if ((ret & 0x02) == 0x02)
data->tcpu_mask |= 0x10;
/* Multi-Function detecting for Volt and TR/TD */
ret = nct7904_read_reg(data, BANK_0, VT_ADC_MD_REG);
if (ret < 0)
return ret;
data->temp_mode = 0;
for (i = 0; i < 4; i++) {
val = (ret >> (i * 2)) & 0x03;
bit = (1 << i);
if (val == VOLT_MONITOR_MODE) {
data->tcpu_mask &= ~bit;
} else if (val == THERMAL_DIODE_MODE && i < 2) {
data->temp_mode |= bit;
data->vsen_mask &= ~(0x06 << (i * 2));
} else if (val == THERMISTOR_MODE) {
data->vsen_mask &= ~(0x02 << (i * 2));
} else {
/* Reserved */
data->tcpu_mask &= ~bit;
data->vsen_mask &= ~(0x06 << (i * 2));
}
}
/* PECI */
ret = nct7904_read_reg(data, BANK_2, PFE_REG);
if (ret < 0)
return ret;
if (ret & 0x80) {
data->enable_dts = 1; /* Enable DTS & PECI */
} else {
ret = nct7904_read_reg(data, BANK_2, TSI_CTRL_REG);
if (ret < 0)
return ret;
if (ret & 0x80)
data->enable_dts = 0x3; /* Enable DTS & TSI */
}
/* Check DTS enable status */
if (data->enable_dts) {
ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL0_REG);
if (ret < 0)
return ret;
data->has_dts = ret & 0xF;
if (data->enable_dts & ENABLE_TSI) {
ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
if (ret < 0)
return ret;
data->has_dts |= (ret & 0xF) << 4;
}
}
for (i = 0; i < FANCTL_MAX; i++) {
ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i);
if (ret < 0)
return ret;
data->fan_mode[i] = ret;
}
/* Read all of SMI status register to clear alarms */
for (i = 0; i < SMI_STS_MAX; i++) {
ret = nct7904_read_reg(data, BANK_0, SMI_STS1_REG + i);
if (ret < 0)
return ret;
}
hwmon_dev =
devm_hwmon_device_register_with_info(dev, client->name, data,
&nct7904_chip_info, NULL);
ret = PTR_ERR_OR_ZERO(hwmon_dev);
if (ret)
return ret;
/* Watchdog initialization */
data->wdt.ops = &nct7904_wdt_ops;
data->wdt.info = &nct7904_wdt_info;
data->wdt.timeout = WATCHDOG_TIMEOUT * 60; /* Set default timeout */
data->wdt.min_timeout = MIN_TIMEOUT;
data->wdt.max_timeout = MAX_TIMEOUT;
data->wdt.parent = &client->dev;
watchdog_init_timeout(&data->wdt, timeout * 60, &client->dev);
watchdog_set_nowayout(&data->wdt, nowayout);
watchdog_set_drvdata(&data->wdt, data);
watchdog_stop_on_unregister(&data->wdt);
return devm_watchdog_register_device(dev, &data->wdt);
}