in fschmd.c [1083:1249]
static int fschmd_probe(struct i2c_client *client)
{
struct fschmd_data *data;
const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
"Heracles", "Heimdall", "Hades", "Syleus" };
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
int i, err;
enum chips kind = i2c_match_id(fschmd_id, client)->driver_data;
data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
mutex_init(&data->watchdog_lock);
INIT_LIST_HEAD(&data->list);
kref_init(&data->kref);
/*
* Store client pointer in our data struct for watchdog usage
* (where the client is found through a data ptr instead of the
* otherway around)
*/
data->client = client;
data->kind = kind;
if (kind == fscpos) {
/*
* The Poseidon has hardwired temp limits, fill these
* in for the alarm resetting code
*/
data->temp_max[0] = 70 + 128;
data->temp_max[1] = 50 + 128;
data->temp_max[2] = 50 + 128;
}
/* Read the special DMI table for fscher and newer chips */
if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
dmi_walk(fschmd_dmi_decode, NULL);
if (dmi_vref == -1) {
dev_warn(&client->dev,
"Couldn't get voltage scaling factors from "
"BIOS DMI table, using builtin defaults\n");
dmi_vref = 33;
}
}
/* Read in some never changing registers */
data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
data->global_control = i2c_smbus_read_byte_data(client,
FSCHMD_REG_CONTROL);
data->watchdog_control = i2c_smbus_read_byte_data(client,
FSCHMD_REG_WDOG_CONTROL[data->kind]);
data->watchdog_state = i2c_smbus_read_byte_data(client,
FSCHMD_REG_WDOG_STATE[data->kind]);
data->watchdog_preset = i2c_smbus_read_byte_data(client,
FSCHMD_REG_WDOG_PRESET[data->kind]);
err = device_create_file(&client->dev, &dev_attr_alert_led);
if (err)
goto exit_detach;
for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
err = device_create_file(&client->dev,
&fschmd_attr[i].dev_attr);
if (err)
goto exit_detach;
}
for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
/* Poseidon doesn't have TEMP_LIMIT registers */
if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
temp_max_show)
continue;
if (kind == fscsyl) {
if (i % 4 == 0)
data->temp_status[i / 4] =
i2c_smbus_read_byte_data(client,
FSCHMD_REG_TEMP_STATE
[data->kind][i / 4]);
if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
continue;
}
err = device_create_file(&client->dev,
&fschmd_temp_attr[i].dev_attr);
if (err)
goto exit_detach;
}
for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
/* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
if (kind == fscpos &&
!strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
"pwm3_auto_point1_pwm"))
continue;
if (kind == fscsyl) {
if (i % 5 == 0)
data->fan_status[i / 5] =
i2c_smbus_read_byte_data(client,
FSCHMD_REG_FAN_STATE
[data->kind][i / 5]);
if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
continue;
}
err = device_create_file(&client->dev,
&fschmd_fan_attr[i].dev_attr);
if (err)
goto exit_detach;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
data->hwmon_dev = NULL;
goto exit_detach;
}
/*
* We take the data_mutex lock early so that watchdog_open() cannot
* run when misc_register() has completed, but we've not yet added
* our data to the watchdog_data_list (and set the default timeout)
*/
mutex_lock(&watchdog_data_mutex);
for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
/* Register our watchdog part */
snprintf(data->watchdog_name, sizeof(data->watchdog_name),
"watchdog%c", (i == 0) ? '\0' : ('0' + i));
data->watchdog_miscdev.name = data->watchdog_name;
data->watchdog_miscdev.fops = &watchdog_fops;
data->watchdog_miscdev.minor = watchdog_minors[i];
err = misc_register(&data->watchdog_miscdev);
if (err == -EBUSY)
continue;
if (err) {
data->watchdog_miscdev.minor = 0;
dev_err(&client->dev,
"Registering watchdog chardev: %d\n", err);
break;
}
list_add(&data->list, &watchdog_data_list);
watchdog_set_timeout(data, 60);
dev_info(&client->dev,
"Registered watchdog chardev major 10, minor: %d\n",
watchdog_minors[i]);
break;
}
if (i == ARRAY_SIZE(watchdog_minors)) {
data->watchdog_miscdev.minor = 0;
dev_warn(&client->dev,
"Couldn't register watchdog chardev (due to no free minor)\n");
}
mutex_unlock(&watchdog_data_mutex);
dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
names[data->kind], (int) data->revision);
return 0;
exit_detach:
fschmd_remove(client); /* will also free data for us */
return err;
}