1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Driver for Samsung Q10 and related laptops: controls the backlight 4 * 5 * Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.com> 6 */ 7 8 #include <linux/module.h> 9 #include <linux/kernel.h> 10 #include <linux/init.h> 11 #include <linux/platform_device.h> 12 #include <linux/backlight.h> 13 #include <linux/dmi.h> 14 #include <linux/acpi.h> 15 16 #define SAMSUNGQ10_BL_MAX_INTENSITY 7 17 18 static acpi_handle ec_handle; 19 20 static bool force; 21 module_param(force, bool, 0); 22 MODULE_PARM_DESC(force, 23 "Disable the DMI check and force the driver to be loaded"); 24 25 static int samsungq10_bl_set_intensity(struct backlight_device *bd) 26 { 27 28 acpi_status status; 29 int i; 30 31 for (i = 0; i < SAMSUNGQ10_BL_MAX_INTENSITY; i++) { 32 status = acpi_evaluate_object(ec_handle, "_Q63", NULL, NULL); 33 if (ACPI_FAILURE(status)) 34 return -EIO; 35 } 36 for (i = 0; i < bd->props.brightness; i++) { 37 status = acpi_evaluate_object(ec_handle, "_Q64", NULL, NULL); 38 if (ACPI_FAILURE(status)) 39 return -EIO; 40 } 41 42 return 0; 43 } 44 45 static const struct backlight_ops samsungq10_bl_ops = { 46 .update_status = samsungq10_bl_set_intensity, 47 }; 48 49 static int samsungq10_probe(struct platform_device *pdev) 50 { 51 52 struct backlight_properties props; 53 struct backlight_device *bd; 54 55 memset(&props, 0, sizeof(struct backlight_properties)); 56 props.type = BACKLIGHT_PLATFORM; 57 props.max_brightness = SAMSUNGQ10_BL_MAX_INTENSITY; 58 bd = backlight_device_register("samsung", &pdev->dev, NULL, 59 &samsungq10_bl_ops, &props); 60 if (IS_ERR(bd)) 61 return PTR_ERR(bd); 62 63 platform_set_drvdata(pdev, bd); 64 65 return 0; 66 } 67 68 static void samsungq10_remove(struct platform_device *pdev) 69 { 70 71 struct backlight_device *bd = platform_get_drvdata(pdev); 72 73 backlight_device_unregister(bd); 74 } 75 76 static struct platform_driver samsungq10_driver = { 77 .driver = { 78 .name = KBUILD_MODNAME, 79 }, 80 .probe = samsungq10_probe, 81 .remove_new = samsungq10_remove, 82 }; 83 84 static struct platform_device *samsungq10_device; 85 86 static int __init dmi_check_callback(const struct dmi_system_id *id) 87 { 88 printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident); 89 return 1; 90 } 91 92 static const struct dmi_system_id samsungq10_dmi_table[] __initconst = { 93 { 94 .ident = "Samsung Q10", 95 .matches = { 96 DMI_MATCH(DMI_SYS_VENDOR, "Samsung"), 97 DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"), 98 }, 99 .callback = dmi_check_callback, 100 }, 101 { 102 .ident = "Samsung Q20", 103 .matches = { 104 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), 105 DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"), 106 }, 107 .callback = dmi_check_callback, 108 }, 109 { 110 .ident = "Samsung Q25", 111 .matches = { 112 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), 113 DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"), 114 }, 115 .callback = dmi_check_callback, 116 }, 117 { 118 .ident = "Dell Latitude X200", 119 .matches = { 120 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 121 DMI_MATCH(DMI_PRODUCT_NAME, "X200"), 122 }, 123 .callback = dmi_check_callback, 124 }, 125 { }, 126 }; 127 MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table); 128 129 static int __init samsungq10_init(void) 130 { 131 if (!force && !dmi_check_system(samsungq10_dmi_table)) 132 return -ENODEV; 133 134 ec_handle = ec_get_handle(); 135 136 if (!ec_handle) 137 return -ENODEV; 138 139 samsungq10_device = platform_create_bundle(&samsungq10_driver, 140 samsungq10_probe, 141 NULL, 0, NULL, 0); 142 143 return PTR_ERR_OR_ZERO(samsungq10_device); 144 } 145 146 static void __exit samsungq10_exit(void) 147 { 148 platform_device_unregister(samsungq10_device); 149 platform_driver_unregister(&samsungq10_driver); 150 } 151 152 module_init(samsungq10_init); 153 module_exit(samsungq10_exit); 154 155 MODULE_AUTHOR("Frederick van der Wyck <fvanderwyck@gmail.com>"); 156 MODULE_DESCRIPTION("Samsung Q10 Driver"); 157 MODULE_LICENSE("GPL"); 158