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 int 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 return 0; 76 } 77 78 static struct platform_driver samsungq10_driver = { 79 .driver = { 80 .name = KBUILD_MODNAME, 81 }, 82 .probe = samsungq10_probe, 83 .remove = samsungq10_remove, 84 }; 85 86 static struct platform_device *samsungq10_device; 87 88 static int __init dmi_check_callback(const struct dmi_system_id *id) 89 { 90 printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident); 91 return 1; 92 } 93 94 static const struct dmi_system_id samsungq10_dmi_table[] __initconst = { 95 { 96 .ident = "Samsung Q10", 97 .matches = { 98 DMI_MATCH(DMI_SYS_VENDOR, "Samsung"), 99 DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"), 100 }, 101 .callback = dmi_check_callback, 102 }, 103 { 104 .ident = "Samsung Q20", 105 .matches = { 106 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), 107 DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"), 108 }, 109 .callback = dmi_check_callback, 110 }, 111 { 112 .ident = "Samsung Q25", 113 .matches = { 114 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), 115 DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"), 116 }, 117 .callback = dmi_check_callback, 118 }, 119 { 120 .ident = "Dell Latitude X200", 121 .matches = { 122 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), 123 DMI_MATCH(DMI_PRODUCT_NAME, "X200"), 124 }, 125 .callback = dmi_check_callback, 126 }, 127 { }, 128 }; 129 MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table); 130 131 static int __init samsungq10_init(void) 132 { 133 if (!force && !dmi_check_system(samsungq10_dmi_table)) 134 return -ENODEV; 135 136 ec_handle = ec_get_handle(); 137 138 if (!ec_handle) 139 return -ENODEV; 140 141 samsungq10_device = platform_create_bundle(&samsungq10_driver, 142 samsungq10_probe, 143 NULL, 0, NULL, 0); 144 145 return PTR_ERR_OR_ZERO(samsungq10_device); 146 } 147 148 static void __exit samsungq10_exit(void) 149 { 150 platform_device_unregister(samsungq10_device); 151 platform_driver_unregister(&samsungq10_driver); 152 } 153 154 module_init(samsungq10_init); 155 module_exit(samsungq10_exit); 156 157 MODULE_AUTHOR("Frederick van der Wyck <fvanderwyck@gmail.com>"); 158 MODULE_DESCRIPTION("Samsung Q10 Driver"); 159 MODULE_LICENSE("GPL"); 160