static int applespi_probe()

in keyboard/applespi.c [1648:1832]


static int applespi_probe(struct spi_device *spi)
{
	struct applespi_data *applespi;
	acpi_handle spi_handle = ACPI_HANDLE(&spi->dev);
	acpi_status acpi_sts;
	int sts, i;
	unsigned long long gpe, usb_status;

	/* check if the USB interface is present and enabled already */
	acpi_sts = acpi_evaluate_integer(spi_handle, "UIST", NULL, &usb_status);
	if (ACPI_SUCCESS(acpi_sts) && usb_status) {
		/* let the USB driver take over instead */
		dev_info(&spi->dev, "USB interface already enabled\n");
		return -ENODEV;
	}

	/* allocate driver data */
	applespi = devm_kzalloc(&spi->dev, sizeof(*applespi), GFP_KERNEL);
	if (!applespi)
		return -ENOMEM;

	applespi->spi = spi;

	INIT_WORK(&applespi->work, applespi_worker);

	/* store the driver data */
	spi_set_drvdata(spi, applespi);

	/* create our buffers */
	applespi->tx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
					   GFP_KERNEL);
	applespi->tx_status = devm_kmalloc(&spi->dev, APPLESPI_STATUS_SIZE,
					   GFP_KERNEL);
	applespi->rx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE,
					   GFP_KERNEL);
	applespi->msg_buf = devm_kmalloc_array(&spi->dev, MAX_PKTS_PER_MSG,
					       APPLESPI_PACKET_SIZE,
					       GFP_KERNEL);

	if (!applespi->tx_buffer || !applespi->tx_status ||
	    !applespi->rx_buffer || !applespi->msg_buf)
		return -ENOMEM;

	/* set up our spi messages */
	applespi_setup_read_txfrs(applespi);
	applespi_setup_write_txfrs(applespi);

	/* cache ACPI method handles */
	acpi_sts = acpi_get_handle(spi_handle, "SIEN", &applespi->sien);
	if (ACPI_FAILURE(acpi_sts)) {
		dev_err(&applespi->spi->dev,
			"Failed to get SIEN ACPI method handle: %s\n",
			acpi_format_exception(acpi_sts));
		return -ENODEV;
	}

	acpi_sts = acpi_get_handle(spi_handle, "SIST", &applespi->sist);
	if (ACPI_FAILURE(acpi_sts)) {
		dev_err(&applespi->spi->dev,
			"Failed to get SIST ACPI method handle: %s\n",
			acpi_format_exception(acpi_sts));
		return -ENODEV;
	}

	/* switch on the SPI interface */
	sts = applespi_setup_spi(applespi);
	if (sts)
		return sts;

	sts = applespi_enable_spi(applespi);
	if (sts)
		return sts;

	/* setup the keyboard input dev */
	applespi->keyboard_input_dev = devm_input_allocate_device(&spi->dev);

	if (!applespi->keyboard_input_dev)
		return -ENOMEM;

	applespi->keyboard_input_dev->name = "Apple SPI Keyboard";
	applespi->keyboard_input_dev->phys = "applespi/input0";
	applespi->keyboard_input_dev->dev.parent = &spi->dev;
	applespi->keyboard_input_dev->id.bustype = BUS_SPI;

	applespi->keyboard_input_dev->evbit[0] =
			BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT_MASK(EV_REP);
	applespi->keyboard_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL);

	input_set_drvdata(applespi->keyboard_input_dev, applespi);
	applespi->keyboard_input_dev->event = applespi_event;

	for (i = 0; i < ARRAY_SIZE(applespi_scancodes); i++)
		if (applespi_scancodes[i])
			input_set_capability(applespi->keyboard_input_dev,
					     EV_KEY, applespi_scancodes[i]);

	for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++)
		if (applespi_controlcodes[i])
			input_set_capability(applespi->keyboard_input_dev,
					     EV_KEY, applespi_controlcodes[i]);

	for (i = 0; i < ARRAY_SIZE(applespi_fn_codes); i++)
		if (applespi_fn_codes[i].to)
			input_set_capability(applespi->keyboard_input_dev,
					     EV_KEY, applespi_fn_codes[i].to);

	input_set_capability(applespi->keyboard_input_dev, EV_KEY, KEY_FN);

	sts = input_register_device(applespi->keyboard_input_dev);
	if (sts) {
		dev_err(&applespi->spi->dev,
			"Unable to register keyboard input device (%d)\n", sts);
		return -ENODEV;
	}

	/*
	 * The applespi device doesn't send interrupts normally (as is described
	 * in its DSDT), but rather seems to use ACPI GPEs.
	 */
	acpi_sts = acpi_evaluate_integer(spi_handle, "_GPE", NULL, &gpe);
	if (ACPI_FAILURE(acpi_sts)) {
		dev_err(&applespi->spi->dev,
			"Failed to obtain GPE for SPI slave device: %s\n",
			acpi_format_exception(acpi_sts));
		return -ENODEV;
	}
	applespi->gpe = (int)gpe;

	acpi_sts = acpi_install_gpe_handler(NULL, applespi->gpe,
					    ACPI_GPE_LEVEL_TRIGGERED,
					    applespi_notify, applespi);
	if (ACPI_FAILURE(acpi_sts)) {
		dev_err(&applespi->spi->dev,
			"Failed to install GPE handler for GPE %d: %s\n",
			applespi->gpe, acpi_format_exception(acpi_sts));
		return -ENODEV;
	}

	applespi->suspended = false;

	acpi_sts = acpi_enable_gpe(NULL, applespi->gpe);
	if (ACPI_FAILURE(acpi_sts)) {
		dev_err(&applespi->spi->dev,
			"Failed to enable GPE handler for GPE %d: %s\n",
			applespi->gpe, acpi_format_exception(acpi_sts));
		acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
		return -ENODEV;
	}

	/* trigger touchpad setup */
	applespi_init(applespi, false);

	/*
	 * By default this device is not enabled for wakeup; but USB keyboards
	 * generally are, so the expectation is that by default the keyboard
	 * will wake the system.
	 */
	device_wakeup_enable(&spi->dev);

	/* set up keyboard-backlight */
	sts = applespi_get_saved_bl_level(applespi);
	if (sts >= 0)
		applespi_set_bl_level(&applespi->backlight_info, sts);

	applespi->backlight_info.name            = "spi::kbd_backlight";
	applespi->backlight_info.default_trigger = "kbd-backlight";
	applespi->backlight_info.brightness_set  = applespi_set_bl_level;

	sts = devm_led_classdev_register(&spi->dev, &applespi->backlight_info);
	if (sts)
		dev_warn(&applespi->spi->dev,
			 "Unable to register keyboard backlight class dev (%d)\n",
			 sts);

	/* set up debugfs entries for touchpad dimensions logging */
	applespi->debugfs_root = debugfs_create_dir("applespi", NULL);

	debugfs_create_bool("enable_tp_dim", 0600, applespi->debugfs_root,
			    &applespi->debug_tp_dim);

	debugfs_create_file("tp_dim", 0400, applespi->debugfs_root, applespi,
			    &applespi_tp_dim_fops);

	return 0;
}