in it87.c [3034:3180]
static int it87_probe(struct platform_device *pdev)
{
struct it87_data *data;
struct resource *res;
struct device *dev = &pdev->dev;
struct it87_sio_data *sio_data = dev_get_platdata(dev);
int enable_pwm_interface;
struct device *hwmon_dev;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
DRVNAME)) {
dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
(unsigned long)res->start,
(unsigned long)(res->start + IT87_EC_EXTENT - 1));
return -EBUSY;
}
data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->addr = res->start;
data->sioaddr = sio_data->sioaddr;
data->type = sio_data->type;
data->features = it87_devices[sio_data->type].features;
data->peci_mask = it87_devices[sio_data->type].peci_mask;
data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
/*
* IT8705F Datasheet 0.4.1, 3h == Version G.
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
* These are the first revisions with 16-bit tachometer support.
*/
switch (data->type) {
case it87:
if (sio_data->revision >= 0x03) {
data->features &= ~FEAT_OLD_AUTOPWM;
data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS;
}
break;
case it8712:
if (sio_data->revision >= 0x08) {
data->features &= ~FEAT_OLD_AUTOPWM;
data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS |
FEAT_FIVE_FANS;
}
break;
default:
break;
}
/* Now, we do the remaining detection. */
if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
it87_read_value(data, IT87_REG_CHIPID) != 0x90)
return -ENODEV;
platform_set_drvdata(pdev, data);
mutex_init(&data->update_lock);
/* Check PWM configuration */
enable_pwm_interface = it87_check_pwm(dev);
if (!enable_pwm_interface)
dev_info(dev,
"Detected broken BIOS defaults, disabling PWM interface\n");
/* Starting with IT8721F, we handle scaling of internal voltages */
if (has_12mv_adc(data)) {
if (sio_data->internal & BIT(0))
data->in_scaled |= BIT(3); /* in3 is AVCC */
if (sio_data->internal & BIT(1))
data->in_scaled |= BIT(7); /* in7 is VSB */
if (sio_data->internal & BIT(2))
data->in_scaled |= BIT(8); /* in8 is Vbat */
if (sio_data->internal & BIT(3))
data->in_scaled |= BIT(9); /* in9 is AVCC */
} else if (sio_data->type == it8781 || sio_data->type == it8782 ||
sio_data->type == it8783) {
if (sio_data->internal & BIT(0))
data->in_scaled |= BIT(3); /* in3 is VCC5V */
if (sio_data->internal & BIT(1))
data->in_scaled |= BIT(7); /* in7 is VCCH5V */
}
data->has_temp = 0x07;
if (sio_data->skip_temp & BIT(2)) {
if (sio_data->type == it8782 &&
!(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
data->has_temp &= ~BIT(2);
}
data->in_internal = sio_data->internal;
data->need_in7_reroute = sio_data->need_in7_reroute;
data->has_in = 0x3ff & ~sio_data->skip_in;
if (has_six_temp(data)) {
u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);
/* Check for additional temperature sensors */
if ((reg & 0x03) >= 0x02)
data->has_temp |= BIT(3);
if (((reg >> 2) & 0x03) >= 0x02)
data->has_temp |= BIT(4);
if (((reg >> 4) & 0x03) >= 0x02)
data->has_temp |= BIT(5);
/* Check for additional voltage sensors */
if ((reg & 0x03) == 0x01)
data->has_in |= BIT(10);
if (((reg >> 2) & 0x03) == 0x01)
data->has_in |= BIT(11);
if (((reg >> 4) & 0x03) == 0x01)
data->has_in |= BIT(12);
}
data->has_beep = !!sio_data->beep_pin;
/* Initialize the IT87 chip */
it87_init_device(pdev);
if (!sio_data->skip_vid) {
data->has_vid = true;
data->vrm = vid_which_vrm();
/* VID reading from Super-I/O config space if available */
data->vid = sio_data->vid_value;
}
/* Prepare for sysfs hooks */
data->groups[0] = &it87_group;
data->groups[1] = &it87_group_in;
data->groups[2] = &it87_group_temp;
data->groups[3] = &it87_group_fan;
if (enable_pwm_interface) {
data->has_pwm = BIT(ARRAY_SIZE(IT87_REG_PWM)) - 1;
data->has_pwm &= ~sio_data->skip_pwm;
data->groups[4] = &it87_group_pwm;
if (has_old_autopwm(data) || has_newer_autopwm(data))
data->groups[5] = &it87_group_auto_pwm;
}
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
it87_devices[sio_data->type].name,
data, data->groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}