static int pc87360_probe()

in pc87360.c [1193:1345]


static int pc87360_probe(struct platform_device *pdev)
{
	int i;
	struct pc87360_data *data;
	int err = 0;
	const char *name;
	int use_thermistors = 0;
	struct device *dev = &pdev->dev;

	data = devm_kzalloc(dev, sizeof(struct pc87360_data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	switch (devid) {
	default:
		name = "pc87360";
		data->fannr = 2;
		break;
	case 0xe8:
		name = "pc87363";
		data->fannr = 2;
		break;
	case 0xe4:
		name = "pc87364";
		data->fannr = 3;
		break;
	case 0xe5:
		name = "pc87365";
		data->fannr = extra_isa[0] ? 3 : 0;
		data->innr = extra_isa[1] ? 11 : 0;
		data->tempnr = extra_isa[2] ? 2 : 0;
		break;
	case 0xe9:
		name = "pc87366";
		data->fannr = extra_isa[0] ? 3 : 0;
		data->innr = extra_isa[1] ? 14 : 0;
		data->tempnr = extra_isa[2] ? 3 : 0;
		break;
	}

	data->name = name;
	mutex_init(&data->lock);
	mutex_init(&data->update_lock);
	platform_set_drvdata(pdev, data);

	for (i = 0; i < LDNI_MAX; i++) {
		data->address[i] = extra_isa[i];
		if (data->address[i]
		 && !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
					 pc87360_driver.driver.name)) {
			dev_err(dev,
				"Region 0x%x-0x%x already in use!\n",
				extra_isa[i], extra_isa[i]+PC87360_EXTENT-1);
			return -EBUSY;
		}
	}

	/* Retrieve the fans configuration from Super-I/O space */
	if (data->fannr)
		data->fan_conf = confreg[0] | (confreg[1] << 8);

	/*
	 * Use the correct reference voltage
	 * Unless both the VLM and the TMS logical devices agree to
	 * use an external Vref, the internal one is used.
	 */
	if (data->innr) {
		i = pc87360_read_value(data, LD_IN, NO_BANK,
				       PC87365_REG_IN_CONFIG);
		if (data->tempnr) {
			i &= pc87360_read_value(data, LD_TEMP, NO_BANK,
						PC87365_REG_TEMP_CONFIG);
		}
		data->in_vref = (i&0x02) ? 3025 : 2966;
		dev_dbg(dev, "Using %s reference voltage\n",
			(i&0x02) ? "external" : "internal");

		data->vid_conf = confreg[3];
		data->vrm = vid_which_vrm();
	}

	/* Fan clock dividers may be needed before any data is read */
	for (i = 0; i < data->fannr; i++) {
		if (FAN_CONFIG_MONITOR(data->fan_conf, i))
			data->fan_status[i] = pc87360_read_value(data,
					      LD_FAN, NO_BANK,
					      PC87360_REG_FAN_STATUS(i));
	}

	if (init > 0) {
		if (devid == 0xe9 && data->address[1]) /* PC87366 */
			use_thermistors = confreg[2] & 0x40;

		pc87360_init_device(pdev, use_thermistors);
	}

	/* Register all-or-nothing sysfs groups */

	if (data->innr) {
		err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group);
		if (err)
			goto error;
	}

	if (data->innr == 14) {
		err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group);
		if (err)
			goto error;
	}

	/* create device attr-files for varying sysfs groups */

	if (data->tempnr) {
		for (i = 0; i < data->tempnr; i++) {
			err = sysfs_create_group(&dev->kobj,
						 &pc8736x_temp_attr_group[i]);
			if (err)
				goto error;
		}
		err = device_create_file(dev, &dev_attr_alarms_temp);
		if (err)
			goto error;
	}

	for (i = 0; i < data->fannr; i++) {
		if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
			err = sysfs_create_group(&dev->kobj,
						 &pc8736x_fan_attr_group[i]);
			if (err)
				goto error;
		}
		if (FAN_CONFIG_CONTROL(data->fan_conf, i)) {
			err = device_create_file(dev, &pwm[i].dev_attr);
			if (err)
				goto error;
		}
	}

	err = device_create_file(dev, &dev_attr_name);
	if (err)
		goto error;

	data->hwmon_dev = hwmon_device_register(dev);
	if (IS_ERR(data->hwmon_dev)) {
		err = PTR_ERR(data->hwmon_dev);
		goto error;
	}
	return 0;

error:
	pc87360_remove_files(dev);
	return err;
}