static int bu21013_probe()

in touchscreen/bu21013_ts.c [407:553]


static int bu21013_probe(struct i2c_client *client,
			 const struct i2c_device_id *id)
{
	struct bu21013_ts *ts;
	struct input_dev *in_dev;
	struct input_absinfo *info;
	u32 max_x = 0, max_y = 0;
	int error;

	if (!i2c_check_functionality(client->adapter,
				     I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(&client->dev, "i2c smbus byte data not supported\n");
		return -EIO;
	}

	if (!client->irq) {
		dev_err(&client->dev, "No IRQ set up\n");
		return -EINVAL;
	}

	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;

	ts->client = client;

	ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x");
	ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y");

	in_dev = devm_input_allocate_device(&client->dev);
	if (!in_dev) {
		dev_err(&client->dev, "device memory alloc failed\n");
		return -ENOMEM;
	}
	ts->in_dev = in_dev;
	input_set_drvdata(in_dev, ts);

	/* register the device to input subsystem */
	in_dev->name = DRIVER_TP;
	in_dev->id.bustype = BUS_I2C;

	device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x);
	device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y);

	input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0);
	input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0);

	touchscreen_parse_properties(in_dev, true, &ts->props);

	/* Adjust for the legacy "flip" properties, if present */
	if (!ts->props.invert_x &&
	    device_property_read_bool(&client->dev, "rohm,flip-x")) {
		info = &in_dev->absinfo[ABS_MT_POSITION_X];
		info->maximum -= info->minimum;
		info->minimum = 0;
	}

	if (!ts->props.invert_y &&
	    device_property_read_bool(&client->dev, "rohm,flip-y")) {
		info = &in_dev->absinfo[ABS_MT_POSITION_Y];
		info->maximum -= info->minimum;
		info->minimum = 0;
	}

	error = input_mt_init_slots(in_dev, MAX_FINGERS,
				    INPUT_MT_DIRECT | INPUT_MT_TRACK |
					INPUT_MT_DROP_UNUSED);
	if (error) {
		dev_err(&client->dev, "failed to initialize MT slots");
		return error;
	}

	ts->regulator = devm_regulator_get(&client->dev, "avdd");
	if (IS_ERR(ts->regulator)) {
		dev_err(&client->dev, "regulator_get failed\n");
		return PTR_ERR(ts->regulator);
	}

	error = regulator_enable(ts->regulator);
	if (error) {
		dev_err(&client->dev, "regulator enable failed\n");
		return error;
	}

	error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts);
	if (error) {
		dev_err(&client->dev, "failed to install power off handler\n");
		return error;
	}

	/* Named "CS" on the chip, DT binding is "reset" */
	ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
	error = PTR_ERR_OR_ZERO(ts->cs_gpiod);
	if (error) {
		if (error != -EPROBE_DEFER)
			dev_err(&client->dev, "failed to get CS GPIO\n");
		return error;
	}
	gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS");

	error = devm_add_action_or_reset(&client->dev,
					 bu21013_disable_chip, ts);
	if (error) {
		dev_err(&client->dev,
			"failed to install chip disable handler\n");
		return error;
	}

	/* Named "INT" on the chip, DT binding is "touch" */
	ts->int_gpiod = devm_gpiod_get_optional(&client->dev,
						"touch", GPIOD_IN);
	error = PTR_ERR_OR_ZERO(ts->int_gpiod);
	if (error) {
		if (error != -EPROBE_DEFER)
			dev_err(&client->dev, "failed to get INT GPIO\n");
		return error;
	}

	if (ts->int_gpiod)
		gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT");

	/* configure the touch panel controller */
	error = bu21013_init_chip(ts);
	if (error) {
		dev_err(&client->dev, "error in bu21013 config\n");
		return error;
	}

	error = devm_request_threaded_irq(&client->dev, client->irq,
					  NULL, bu21013_gpio_irq,
					  IRQF_ONESHOT, DRIVER_TP, ts);
	if (error) {
		dev_err(&client->dev, "request irq %d failed\n",
			client->irq);
		return error;
	}

	error = input_register_device(in_dev);
	if (error) {
		dev_err(&client->dev, "failed to register input device\n");
		return error;
	}

	i2c_set_clientdata(client, ts);

	return 0;
}