static int wm831x_ts_probe()

in touchscreen/wm831x-ts.c [231:375]


static int wm831x_ts_probe(struct platform_device *pdev)
{
	struct wm831x_ts *wm831x_ts;
	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
	struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent);
	struct wm831x_touch_pdata *pdata = NULL;
	struct input_dev *input_dev;
	int error, irqf;

	if (core_pdata)
		pdata = core_pdata->touch;

	wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts),
				 GFP_KERNEL);
	input_dev = devm_input_allocate_device(&pdev->dev);
	if (!wm831x_ts || !input_dev) {
		error = -ENOMEM;
		goto err_alloc;
	}

	wm831x_ts->wm831x = wm831x;
	wm831x_ts->input_dev = input_dev;
	INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work);

	/*
	 * If we have a direct IRQ use it, otherwise use the interrupt
	 * from the WM831x IRQ controller.
	 */
	wm831x_ts->data_irq = wm831x_irq(wm831x,
					 platform_get_irq_byname(pdev,
								 "TCHDATA"));
	if (pdata && pdata->data_irq)
		wm831x_ts->data_irq = pdata->data_irq;

	wm831x_ts->pd_irq = wm831x_irq(wm831x,
				       platform_get_irq_byname(pdev, "TCHPD"));
	if (pdata && pdata->pd_irq)
		wm831x_ts->pd_irq = pdata->pd_irq;

	if (pdata)
		wm831x_ts->pressure = pdata->pressure;
	else
		wm831x_ts->pressure = true;

	/* Five wire touchscreens can't report pressure */
	if (pdata && pdata->fivewire) {
		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
				WM831X_TCH_5WIRE, WM831X_TCH_5WIRE);

		/* Pressure measurements are not possible for five wire mode */
		WARN_ON(pdata->pressure && pdata->fivewire);
		wm831x_ts->pressure = false;
	} else {
		wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
				WM831X_TCH_5WIRE, 0);
	}

	if (pdata) {
		switch (pdata->isel) {
		default:
			dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n",
				pdata->isel);
			fallthrough;
		case 200:
		case 0:
			wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
					WM831X_TCH_ISEL, 0);
			break;
		case 400:
			wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
					WM831X_TCH_ISEL, WM831X_TCH_ISEL);
			break;
		}
	}

	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2,
			WM831X_TCH_PDONLY, 0);

	/* Default to 96 samples/sec */
	wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1,
			WM831X_TCH_RATE_MASK, 6);

	if (pdata && pdata->data_irqf)
		irqf = pdata->data_irqf;
	else
		irqf = IRQF_TRIGGER_HIGH;

	error = request_threaded_irq(wm831x_ts->data_irq,
				     NULL, wm831x_ts_data_irq,
				     irqf | IRQF_ONESHOT | IRQF_NO_AUTOEN,
				     "Touchscreen data", wm831x_ts);
	if (error) {
		dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n",
			wm831x_ts->data_irq, error);
		goto err_alloc;
	}

	if (pdata && pdata->pd_irqf)
		irqf = pdata->pd_irqf;
	else
		irqf = IRQF_TRIGGER_HIGH;

	error = request_threaded_irq(wm831x_ts->pd_irq,
				     NULL, wm831x_ts_pen_down_irq,
				     irqf | IRQF_ONESHOT,
				     "Touchscreen pen down", wm831x_ts);
	if (error) {
		dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n",
			wm831x_ts->pd_irq, error);
		goto err_data_irq;
	}

	/* set up touch configuration */
	input_dev->name = "WM831x touchscreen";
	input_dev->phys = "wm831x";
	input_dev->open = wm831x_ts_input_open;
	input_dev->close = wm831x_ts_input_close;

	__set_bit(EV_ABS, input_dev->evbit);
	__set_bit(EV_KEY, input_dev->evbit);
	__set_bit(BTN_TOUCH, input_dev->keybit);

	input_set_abs_params(input_dev, ABS_X, 0, 4095, 5, 0);
	input_set_abs_params(input_dev, ABS_Y, 0, 4095, 5, 0);
	if (wm831x_ts->pressure)
		input_set_abs_params(input_dev, ABS_PRESSURE, 0, 4095, 5, 0);

	input_set_drvdata(input_dev, wm831x_ts);
	input_dev->dev.parent = &pdev->dev;

	error = input_register_device(input_dev);
	if (error)
		goto err_pd_irq;

	platform_set_drvdata(pdev, wm831x_ts);
	return 0;

err_pd_irq:
	free_irq(wm831x_ts->pd_irq, wm831x_ts);
err_data_irq:
	free_irq(wm831x_ts->data_irq, wm831x_ts);
err_alloc:

	return error;
}