static int ccs811_probe()

in chemical/ccs811.c [404:533]


static int ccs811_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct iio_dev *indio_dev;
	struct ccs811_data *data;
	int ret;

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
				     | I2C_FUNC_SMBUS_BYTE_DATA
				     | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
		return -EOPNOTSUPP;

	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
	if (!indio_dev)
		return -ENOMEM;

	data = iio_priv(indio_dev);
	i2c_set_clientdata(client, indio_dev);
	data->client = client;

	data->wakeup_gpio = devm_gpiod_get_optional(&client->dev, "wakeup",
						    GPIOD_OUT_HIGH);
	if (IS_ERR(data->wakeup_gpio))
		return PTR_ERR(data->wakeup_gpio);

	ccs811_set_wakeup(data, true);

	ret = ccs811_reset(client);
	if (ret) {
		ccs811_set_wakeup(data, false);
		return ret;
	}

	/* Check hardware id (should be 0x81 for this family of devices) */
	ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
	if (ret < 0) {
		ccs811_set_wakeup(data, false);
		return ret;
	}

	if (ret != CCS811_HW_ID_VALUE) {
		dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
		ccs811_set_wakeup(data, false);
		return -ENODEV;
	}

	ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
	if (ret < 0) {
		ccs811_set_wakeup(data, false);
		return ret;
	}

	if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
		dev_err(&client->dev, "no CCS811 sensor\n");
		ccs811_set_wakeup(data, false);
		return -ENODEV;
	}

	ret = ccs811_setup(client);
	if (ret < 0) {
		ccs811_set_wakeup(data, false);
		return ret;
	}

	ccs811_set_wakeup(data, false);

	mutex_init(&data->lock);

	indio_dev->name = id->name;
	indio_dev->info = &ccs811_info;
	indio_dev->modes = INDIO_DIRECT_MODE;

	indio_dev->channels = ccs811_channels;
	indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);

	if (client->irq > 0) {
		ret = devm_request_threaded_irq(&client->dev, client->irq,
						ccs811_data_rdy_trigger_poll,
						NULL,
						IRQF_TRIGGER_FALLING |
						IRQF_ONESHOT,
						"ccs811_irq", indio_dev);
		if (ret) {
			dev_err(&client->dev, "irq request error %d\n", -ret);
			goto err_poweroff;
		}

		data->drdy_trig = devm_iio_trigger_alloc(&client->dev,
							 "%s-dev%d",
							 indio_dev->name,
							 iio_device_id(indio_dev));
		if (!data->drdy_trig) {
			ret = -ENOMEM;
			goto err_poweroff;
		}

		data->drdy_trig->ops = &ccs811_trigger_ops;
		iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
		indio_dev->trig = data->drdy_trig;
		iio_trigger_get(indio_dev->trig);
		ret = iio_trigger_register(data->drdy_trig);
		if (ret)
			goto err_poweroff;
	}

	ret = iio_triggered_buffer_setup(indio_dev, NULL,
					 ccs811_trigger_handler, NULL);

	if (ret < 0) {
		dev_err(&client->dev, "triggered buffer setup failed\n");
		goto err_trigger_unregister;
	}

	ret = iio_device_register(indio_dev);
	if (ret < 0) {
		dev_err(&client->dev, "unable to register iio device\n");
		goto err_buffer_cleanup;
	}
	return 0;

err_buffer_cleanup:
	iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister:
	if (data->drdy_trig)
		iio_trigger_unregister(data->drdy_trig);
err_poweroff:
	i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE, CCS811_MODE_IDLE);

	return ret;
}