xref: /openbmc/linux/drivers/platform/chrome/chromeos_privacy_screen.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
13fb57847SRajat Jain // SPDX-License-Identifier: GPL-2.0
23fb57847SRajat Jain 
33fb57847SRajat Jain /*
43fb57847SRajat Jain  *  ChromeOS Privacy Screen support
53fb57847SRajat Jain  *
63fb57847SRajat Jain  * Copyright (C) 2022 Google LLC
73fb57847SRajat Jain  *
83fb57847SRajat Jain  * This is the Chromeos privacy screen provider, present on certain chromebooks,
93fb57847SRajat Jain  * represented by a GOOG0010 device in the ACPI. This ACPI device, if present,
103fb57847SRajat Jain  * will cause the i915 drm driver to probe defer until this driver registers
113fb57847SRajat Jain  * the privacy-screen.
123fb57847SRajat Jain  */
133fb57847SRajat Jain 
143fb57847SRajat Jain #include <linux/acpi.h>
153fb57847SRajat Jain #include <drm/drm_privacy_screen_driver.h>
163fb57847SRajat Jain 
173fb57847SRajat Jain /*
183fb57847SRajat Jain  * The DSM (Device Specific Method) constants below are the agreed API with
193fb57847SRajat Jain  * the firmware team, on how to control privacy screen using ACPI methods.
203fb57847SRajat Jain  */
213fb57847SRajat Jain #define PRIV_SCRN_DSM_REVID		1	/* DSM version */
223fb57847SRajat Jain #define PRIV_SCRN_DSM_FN_GET_STATUS	1	/* Get privacy screen status */
233fb57847SRajat Jain #define PRIV_SCRN_DSM_FN_ENABLE		2	/* Enable privacy screen */
243fb57847SRajat Jain #define PRIV_SCRN_DSM_FN_DISABLE	3	/* Disable privacy screen */
253fb57847SRajat Jain 
263fb57847SRajat Jain static const guid_t chromeos_privacy_screen_dsm_guid =
273fb57847SRajat Jain 		    GUID_INIT(0xc7033113, 0x8720, 0x4ceb,
283fb57847SRajat Jain 			      0x90, 0x90, 0x9d, 0x52, 0xb3, 0xe5, 0x2d, 0x73);
293fb57847SRajat Jain 
303fb57847SRajat Jain static void
chromeos_privacy_screen_get_hw_state(struct drm_privacy_screen * drm_privacy_screen)313fb57847SRajat Jain chromeos_privacy_screen_get_hw_state(struct drm_privacy_screen
323fb57847SRajat Jain 				     *drm_privacy_screen)
333fb57847SRajat Jain {
343fb57847SRajat Jain 	union acpi_object *obj;
353fb57847SRajat Jain 	acpi_handle handle;
363fb57847SRajat Jain 	struct device *privacy_screen =
373fb57847SRajat Jain 		drm_privacy_screen_get_drvdata(drm_privacy_screen);
383fb57847SRajat Jain 
393fb57847SRajat Jain 	handle = acpi_device_handle(to_acpi_device(privacy_screen));
403fb57847SRajat Jain 	obj = acpi_evaluate_dsm(handle, &chromeos_privacy_screen_dsm_guid,
413fb57847SRajat Jain 				PRIV_SCRN_DSM_REVID,
423fb57847SRajat Jain 				PRIV_SCRN_DSM_FN_GET_STATUS, NULL);
433fb57847SRajat Jain 	if (!obj) {
443fb57847SRajat Jain 		dev_err(privacy_screen,
453fb57847SRajat Jain 			"_DSM failed to get privacy-screen state\n");
463fb57847SRajat Jain 		return;
473fb57847SRajat Jain 	}
483fb57847SRajat Jain 
493fb57847SRajat Jain 	if (obj->type != ACPI_TYPE_INTEGER)
503fb57847SRajat Jain 		dev_err(privacy_screen,
513fb57847SRajat Jain 			"Bad _DSM to get privacy-screen state\n");
523fb57847SRajat Jain 	else if (obj->integer.value == 1)
533fb57847SRajat Jain 		drm_privacy_screen->hw_state = drm_privacy_screen->sw_state =
543fb57847SRajat Jain 			PRIVACY_SCREEN_ENABLED;
553fb57847SRajat Jain 	else
563fb57847SRajat Jain 		drm_privacy_screen->hw_state = drm_privacy_screen->sw_state =
573fb57847SRajat Jain 			PRIVACY_SCREEN_DISABLED;
583fb57847SRajat Jain 
593fb57847SRajat Jain 	ACPI_FREE(obj);
603fb57847SRajat Jain }
613fb57847SRajat Jain 
623fb57847SRajat Jain static int
chromeos_privacy_screen_set_sw_state(struct drm_privacy_screen * drm_privacy_screen,enum drm_privacy_screen_status state)633fb57847SRajat Jain chromeos_privacy_screen_set_sw_state(struct drm_privacy_screen
643fb57847SRajat Jain 				     *drm_privacy_screen,
653fb57847SRajat Jain 				     enum drm_privacy_screen_status state)
663fb57847SRajat Jain {
673fb57847SRajat Jain 	union acpi_object *obj = NULL;
683fb57847SRajat Jain 	acpi_handle handle;
693fb57847SRajat Jain 	struct device *privacy_screen =
703fb57847SRajat Jain 		drm_privacy_screen_get_drvdata(drm_privacy_screen);
713fb57847SRajat Jain 
723fb57847SRajat Jain 	handle = acpi_device_handle(to_acpi_device(privacy_screen));
733fb57847SRajat Jain 
743fb57847SRajat Jain 	if (state == PRIVACY_SCREEN_DISABLED) {
753fb57847SRajat Jain 		obj = acpi_evaluate_dsm(handle,
763fb57847SRajat Jain 					&chromeos_privacy_screen_dsm_guid,
773fb57847SRajat Jain 					PRIV_SCRN_DSM_REVID,
783fb57847SRajat Jain 					PRIV_SCRN_DSM_FN_DISABLE, NULL);
793fb57847SRajat Jain 	} else if (state == PRIVACY_SCREEN_ENABLED) {
803fb57847SRajat Jain 		obj = acpi_evaluate_dsm(handle,
813fb57847SRajat Jain 					&chromeos_privacy_screen_dsm_guid,
823fb57847SRajat Jain 					PRIV_SCRN_DSM_REVID,
833fb57847SRajat Jain 					PRIV_SCRN_DSM_FN_ENABLE, NULL);
843fb57847SRajat Jain 	} else {
853fb57847SRajat Jain 		dev_err(privacy_screen,
863fb57847SRajat Jain 			"Bad attempt to set privacy-screen status to %u\n",
873fb57847SRajat Jain 			state);
883fb57847SRajat Jain 		return -EINVAL;
893fb57847SRajat Jain 	}
903fb57847SRajat Jain 
913fb57847SRajat Jain 	if (!obj) {
923fb57847SRajat Jain 		dev_err(privacy_screen,
933fb57847SRajat Jain 			"_DSM failed to set privacy-screen state\n");
943fb57847SRajat Jain 		return -EIO;
953fb57847SRajat Jain 	}
963fb57847SRajat Jain 
973fb57847SRajat Jain 	drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = state;
983fb57847SRajat Jain 	ACPI_FREE(obj);
993fb57847SRajat Jain 	return 0;
1003fb57847SRajat Jain }
1013fb57847SRajat Jain 
1023fb57847SRajat Jain static const struct drm_privacy_screen_ops chromeos_privacy_screen_ops = {
1033fb57847SRajat Jain 	.get_hw_state = chromeos_privacy_screen_get_hw_state,
1043fb57847SRajat Jain 	.set_sw_state = chromeos_privacy_screen_set_sw_state,
1053fb57847SRajat Jain };
1063fb57847SRajat Jain 
chromeos_privacy_screen_add(struct acpi_device * adev)1073fb57847SRajat Jain static int chromeos_privacy_screen_add(struct acpi_device *adev)
1083fb57847SRajat Jain {
1093fb57847SRajat Jain 	struct drm_privacy_screen *drm_privacy_screen =
1103fb57847SRajat Jain 		drm_privacy_screen_register(&adev->dev,
1113fb57847SRajat Jain 					    &chromeos_privacy_screen_ops,
1123fb57847SRajat Jain 					    &adev->dev);
1133fb57847SRajat Jain 
1143fb57847SRajat Jain 	if (IS_ERR(drm_privacy_screen)) {
1153fb57847SRajat Jain 		dev_err(&adev->dev, "Error registering privacy-screen\n");
1163fb57847SRajat Jain 		return PTR_ERR(drm_privacy_screen);
1173fb57847SRajat Jain 	}
1183fb57847SRajat Jain 
1193fb57847SRajat Jain 	adev->driver_data = drm_privacy_screen;
1203fb57847SRajat Jain 	dev_info(&adev->dev, "registered privacy-screen '%s'\n",
1213fb57847SRajat Jain 		 dev_name(&drm_privacy_screen->dev));
1223fb57847SRajat Jain 
1233fb57847SRajat Jain 	return 0;
1243fb57847SRajat Jain }
1253fb57847SRajat Jain 
chromeos_privacy_screen_remove(struct acpi_device * adev)126*6c0eb5baSDawei Li static void chromeos_privacy_screen_remove(struct acpi_device *adev)
1273fb57847SRajat Jain {
1283fb57847SRajat Jain 	struct drm_privacy_screen *drm_privacy_screen =	acpi_driver_data(adev);
1293fb57847SRajat Jain 
1303fb57847SRajat Jain 	drm_privacy_screen_unregister(drm_privacy_screen);
1313fb57847SRajat Jain }
1323fb57847SRajat Jain 
1333fb57847SRajat Jain static const struct acpi_device_id chromeos_privacy_screen_device_ids[] = {
1343fb57847SRajat Jain 	{"GOOG0010", 0}, /* Google's electronic privacy screen for eDP-1 */
1353fb57847SRajat Jain 	{}
1363fb57847SRajat Jain };
1373fb57847SRajat Jain MODULE_DEVICE_TABLE(acpi, chromeos_privacy_screen_device_ids);
1383fb57847SRajat Jain 
1393fb57847SRajat Jain static struct acpi_driver chromeos_privacy_screen_driver = {
1403fb57847SRajat Jain 	.name = "chromeos_privacy_screen_driver",
1413fb57847SRajat Jain 	.class = "ChromeOS",
1423fb57847SRajat Jain 	.ids = chromeos_privacy_screen_device_ids,
1433fb57847SRajat Jain 	.ops = {
1443fb57847SRajat Jain 		.add = chromeos_privacy_screen_add,
1453fb57847SRajat Jain 		.remove = chromeos_privacy_screen_remove,
1463fb57847SRajat Jain 	},
1473fb57847SRajat Jain };
1483fb57847SRajat Jain 
1493fb57847SRajat Jain module_acpi_driver(chromeos_privacy_screen_driver);
1503fb57847SRajat Jain MODULE_LICENSE("GPL v2");
1513fb57847SRajat Jain MODULE_DESCRIPTION("ChromeOS ACPI Privacy Screen driver");
1523fb57847SRajat Jain MODULE_AUTHOR("Rajat Jain <rajatja@google.com>");
153