2 * Samsung Laptop driver
4 * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de)
5 * Copyright (C) 2009,2011 Novell Inc.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/delay.h>
18 #include <linux/pci.h>
19 #include <linux/backlight.h>
21 #include <linux/dmi.h>
22 #include <linux/platform_device.h>
23 #include <linux/rfkill.h>
26 * This driver is needed because a number of Samsung laptops do not hook
27 * their control settings through ACPI. So we have to poke around in the
28 * BIOS to do things like brightness values, and "special" key controls.
32 * We have 0 - 8 as valid brightness levels. The specs say that level 0 should
33 * be reserved by the BIOS (which really doesn't make much sense), we tell
34 * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8
36 #define MAX_BRIGHT 0x07
39 #define SABI_IFACE_MAIN 0x00
40 #define SABI_IFACE_SUB 0x02
41 #define SABI_IFACE_COMPLETE 0x04
42 #define SABI_IFACE_DATA 0x05
44 /* Structure to get data back to the calling function */
49 struct sabi_header_offsets
{
58 struct sabi_commands
{
60 * Brightness is 0 - 8, as described above.
61 * Value 0 is for the BIOS to use
68 * 0x00 - wireless is off
69 * 0x01 - wireless is on
73 * TODO, verify 3G is correct, that doesn't seem right...
75 u8 get_wireless_button
;
76 u8 set_wireless_button
;
78 /* 0 is off, 1 is on */
83 * 0x80 or 0x00 - no action
84 * 0x81 - recovery key pressed
90 * on seclinux: 0 is low, 1 is high,
91 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
93 u8 get_performance_level
;
94 u8 set_performance_level
;
97 * Tell the BIOS that Linux is running on this machine.
103 struct sabi_performance_level
{
109 const char *test_string
;
111 const struct sabi_header_offsets header_offsets
;
112 const struct sabi_commands commands
;
113 const struct sabi_performance_level performance_levels
[4];
118 static const struct sabi_config sabi_configs
[] = {
120 .test_string
= "SECLINUX",
122 .main_function
= 0x4c49,
130 .data_segment
= 0x07,
134 .get_brightness
= 0x00,
135 .set_brightness
= 0x01,
137 .get_wireless_button
= 0x02,
138 .set_wireless_button
= 0x03,
140 .get_backlight
= 0x04,
141 .set_backlight
= 0x05,
143 .get_recovery_mode
= 0x06,
144 .set_recovery_mode
= 0x07,
146 .get_performance_level
= 0x08,
147 .set_performance_level
= 0x09,
152 .performance_levels
= {
167 .test_string
= "SwSmi@",
169 .main_function
= 0x5843,
177 .data_segment
= 0x07,
181 .get_brightness
= 0x10,
182 .set_brightness
= 0x11,
184 .get_wireless_button
= 0x12,
185 .set_wireless_button
= 0x13,
187 .get_backlight
= 0x2d,
188 .set_backlight
= 0x2e,
190 .get_recovery_mode
= 0xff,
191 .set_recovery_mode
= 0xff,
193 .get_performance_level
= 0x31,
194 .set_performance_level
= 0x32,
199 .performance_levels
= {
220 static const struct sabi_config
*sabi_config
;
222 static void __iomem
*sabi
;
223 static void __iomem
*sabi_iface
;
224 static void __iomem
*f0000_segment
;
225 static struct backlight_device
*backlight_device
;
226 static struct mutex sabi_mutex
;
227 static struct platform_device
*sdev
;
228 static struct rfkill
*rfk
;
231 module_param(force
, bool, 0);
232 MODULE_PARM_DESC(force
,
233 "Disable the DMI check and forces the driver to be loaded");
236 module_param(debug
, bool, S_IRUGO
| S_IWUSR
);
237 MODULE_PARM_DESC(debug
, "Debug enabled or not");
239 static int sabi_get_command(u8 command
, struct sabi_retval
*sretval
)
242 u16 port
= readw(sabi
+ sabi_config
->header_offsets
.port
);
243 u8 complete
, iface_data
;
245 mutex_lock(&sabi_mutex
);
247 /* enable memory to be able to write to it */
248 outb(readb(sabi
+ sabi_config
->header_offsets
.en_mem
), port
);
250 /* write out the command */
251 writew(sabi_config
->main_function
, sabi_iface
+ SABI_IFACE_MAIN
);
252 writew(command
, sabi_iface
+ SABI_IFACE_SUB
);
253 writeb(0, sabi_iface
+ SABI_IFACE_COMPLETE
);
254 outb(readb(sabi
+ sabi_config
->header_offsets
.iface_func
), port
);
256 /* write protect memory to make it safe */
257 outb(readb(sabi
+ sabi_config
->header_offsets
.re_mem
), port
);
259 /* see if the command actually succeeded */
260 complete
= readb(sabi_iface
+ SABI_IFACE_COMPLETE
);
261 iface_data
= readb(sabi_iface
+ SABI_IFACE_DATA
);
262 if (complete
!= 0xaa || iface_data
== 0xff) {
263 pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
264 command
, complete
, iface_data
);
269 * Save off the data into a structure so the caller use it.
270 * Right now we only want the first 4 bytes,
271 * There are commands that need more, but not for the ones we
272 * currently care about.
274 sretval
->retval
[0] = readb(sabi_iface
+ SABI_IFACE_DATA
);
275 sretval
->retval
[1] = readb(sabi_iface
+ SABI_IFACE_DATA
+ 1);
276 sretval
->retval
[2] = readb(sabi_iface
+ SABI_IFACE_DATA
+ 2);
277 sretval
->retval
[3] = readb(sabi_iface
+ SABI_IFACE_DATA
+ 3);
280 mutex_unlock(&sabi_mutex
);
285 static int sabi_set_command(u8 command
, u8 data
)
288 u16 port
= readw(sabi
+ sabi_config
->header_offsets
.port
);
289 u8 complete
, iface_data
;
291 mutex_lock(&sabi_mutex
);
293 /* enable memory to be able to write to it */
294 outb(readb(sabi
+ sabi_config
->header_offsets
.en_mem
), port
);
296 /* write out the command */
297 writew(sabi_config
->main_function
, sabi_iface
+ SABI_IFACE_MAIN
);
298 writew(command
, sabi_iface
+ SABI_IFACE_SUB
);
299 writeb(0, sabi_iface
+ SABI_IFACE_COMPLETE
);
300 writeb(data
, sabi_iface
+ SABI_IFACE_DATA
);
301 outb(readb(sabi
+ sabi_config
->header_offsets
.iface_func
), port
);
303 /* write protect memory to make it safe */
304 outb(readb(sabi
+ sabi_config
->header_offsets
.re_mem
), port
);
306 /* see if the command actually succeeded */
307 complete
= readb(sabi_iface
+ SABI_IFACE_COMPLETE
);
308 iface_data
= readb(sabi_iface
+ SABI_IFACE_DATA
);
309 if (complete
!= 0xaa || iface_data
== 0xff) {
310 pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n",
311 command
, complete
, iface_data
);
315 mutex_unlock(&sabi_mutex
);
319 static void test_backlight(void)
321 struct sabi_retval sretval
;
323 sabi_get_command(sabi_config
->commands
.get_backlight
, &sretval
);
324 printk(KERN_DEBUG
"backlight = 0x%02x\n", sretval
.retval
[0]);
326 sabi_set_command(sabi_config
->commands
.set_backlight
, 0);
327 printk(KERN_DEBUG
"backlight should be off\n");
329 sabi_get_command(sabi_config
->commands
.get_backlight
, &sretval
);
330 printk(KERN_DEBUG
"backlight = 0x%02x\n", sretval
.retval
[0]);
334 sabi_set_command(sabi_config
->commands
.set_backlight
, 1);
335 printk(KERN_DEBUG
"backlight should be on\n");
337 sabi_get_command(sabi_config
->commands
.get_backlight
, &sretval
);
338 printk(KERN_DEBUG
"backlight = 0x%02x\n", sretval
.retval
[0]);
341 static void test_wireless(void)
343 struct sabi_retval sretval
;
345 sabi_get_command(sabi_config
->commands
.get_wireless_button
, &sretval
);
346 printk(KERN_DEBUG
"wireless led = 0x%02x\n", sretval
.retval
[0]);
348 sabi_set_command(sabi_config
->commands
.set_wireless_button
, 0);
349 printk(KERN_DEBUG
"wireless led should be off\n");
351 sabi_get_command(sabi_config
->commands
.get_wireless_button
, &sretval
);
352 printk(KERN_DEBUG
"wireless led = 0x%02x\n", sretval
.retval
[0]);
356 sabi_set_command(sabi_config
->commands
.set_wireless_button
, 1);
357 printk(KERN_DEBUG
"wireless led should be on\n");
359 sabi_get_command(sabi_config
->commands
.get_wireless_button
, &sretval
);
360 printk(KERN_DEBUG
"wireless led = 0x%02x\n", sretval
.retval
[0]);
363 static u8
read_brightness(void)
365 struct sabi_retval sretval
;
366 int user_brightness
= 0;
369 retval
= sabi_get_command(sabi_config
->commands
.get_brightness
,
372 user_brightness
= sretval
.retval
[0];
373 if (user_brightness
!= 0)
374 user_brightness
-= sabi_config
->min_brightness
;
376 return user_brightness
;
379 static void set_brightness(u8 user_brightness
)
381 u8 user_level
= user_brightness
- sabi_config
->min_brightness
;
383 sabi_set_command(sabi_config
->commands
.set_brightness
, user_level
);
386 static int get_brightness(struct backlight_device
*bd
)
388 return (int)read_brightness();
391 static int update_status(struct backlight_device
*bd
)
393 set_brightness(bd
->props
.brightness
);
395 if (bd
->props
.power
== FB_BLANK_UNBLANK
)
396 sabi_set_command(sabi_config
->commands
.set_backlight
, 1);
398 sabi_set_command(sabi_config
->commands
.set_backlight
, 0);
402 static const struct backlight_ops backlight_ops
= {
403 .get_brightness
= get_brightness
,
404 .update_status
= update_status
,
407 static int rfkill_set(void *data
, bool blocked
)
409 /* Do something with blocked...*/
411 * blocked == false is on
412 * blocked == true is off
415 sabi_set_command(sabi_config
->commands
.set_wireless_button
, 0);
417 sabi_set_command(sabi_config
->commands
.set_wireless_button
, 1);
422 static struct rfkill_ops rfkill_ops
= {
423 .set_block
= rfkill_set
,
426 static int init_wireless(struct platform_device
*sdev
)
430 rfk
= rfkill_alloc("samsung-wifi", &sdev
->dev
, RFKILL_TYPE_WLAN
,
435 retval
= rfkill_register(rfk
);
444 static void destroy_wireless(void)
446 rfkill_unregister(rfk
);
450 static ssize_t
get_performance_level(struct device
*dev
,
451 struct device_attribute
*attr
, char *buf
)
453 struct sabi_retval sretval
;
458 retval
= sabi_get_command(sabi_config
->commands
.get_performance_level
,
463 /* The logic is backwards, yeah, lots of fun... */
464 for (i
= 0; sabi_config
->performance_levels
[i
].name
; ++i
) {
465 if (sretval
.retval
[0] == sabi_config
->performance_levels
[i
].value
)
466 return sprintf(buf
, "%s\n", sabi_config
->performance_levels
[i
].name
);
468 return sprintf(buf
, "%s\n", "unknown");
471 static ssize_t
set_performance_level(struct device
*dev
,
472 struct device_attribute
*attr
, const char *buf
,
477 for (i
= 0; sabi_config
->performance_levels
[i
].name
; ++i
) {
478 const struct sabi_performance_level
*level
=
479 &sabi_config
->performance_levels
[i
];
480 if (!strncasecmp(level
->name
, buf
, strlen(level
->name
))) {
481 sabi_set_command(sabi_config
->commands
.set_performance_level
,
486 if (!sabi_config
->performance_levels
[i
].name
)
491 static DEVICE_ATTR(performance_level
, S_IWUSR
| S_IRUGO
,
492 get_performance_level
, set_performance_level
);
495 static int __init
dmi_check_cb(const struct dmi_system_id
*id
)
497 pr_info("found laptop model '%s'\n",
502 static struct dmi_system_id __initdata samsung_dmi_table
[] = {
506 DMI_MATCH(DMI_SYS_VENDOR
,
507 "SAMSUNG ELECTRONICS CO., LTD."),
508 DMI_MATCH(DMI_PRODUCT_NAME
, "N128"),
509 DMI_MATCH(DMI_BOARD_NAME
, "N128"),
511 .callback
= dmi_check_cb
,
516 DMI_MATCH(DMI_SYS_VENDOR
,
517 "SAMSUNG ELECTRONICS CO., LTD."),
518 DMI_MATCH(DMI_PRODUCT_NAME
, "N130"),
519 DMI_MATCH(DMI_BOARD_NAME
, "N130"),
521 .callback
= dmi_check_cb
,
526 DMI_MATCH(DMI_SYS_VENDOR
,
527 "SAMSUNG ELECTRONICS CO., LTD."),
528 DMI_MATCH(DMI_PRODUCT_NAME
, "N510"),
529 DMI_MATCH(DMI_BOARD_NAME
, "N510"),
531 .callback
= dmi_check_cb
,
536 DMI_MATCH(DMI_SYS_VENDOR
,
537 "SAMSUNG ELECTRONICS CO., LTD."),
538 DMI_MATCH(DMI_PRODUCT_NAME
, "X125"),
539 DMI_MATCH(DMI_BOARD_NAME
, "X125"),
541 .callback
= dmi_check_cb
,
544 .ident
= "X120/X170",
546 DMI_MATCH(DMI_SYS_VENDOR
,
547 "SAMSUNG ELECTRONICS CO., LTD."),
548 DMI_MATCH(DMI_PRODUCT_NAME
, "X120/X170"),
549 DMI_MATCH(DMI_BOARD_NAME
, "X120/X170"),
551 .callback
= dmi_check_cb
,
556 DMI_MATCH(DMI_SYS_VENDOR
,
557 "SAMSUNG ELECTRONICS CO., LTD."),
558 DMI_MATCH(DMI_PRODUCT_NAME
, "NC10"),
559 DMI_MATCH(DMI_BOARD_NAME
, "NC10"),
561 .callback
= dmi_check_cb
,
566 DMI_MATCH(DMI_SYS_VENDOR
,
567 "SAMSUNG ELECTRONICS CO., LTD."),
568 DMI_MATCH(DMI_PRODUCT_NAME
, "SQ45S70S"),
569 DMI_MATCH(DMI_BOARD_NAME
, "SQ45S70S"),
571 .callback
= dmi_check_cb
,
576 DMI_MATCH(DMI_SYS_VENDOR
,
577 "SAMSUNG ELECTRONICS CO., LTD."),
578 DMI_MATCH(DMI_PRODUCT_NAME
, "X360"),
579 DMI_MATCH(DMI_BOARD_NAME
, "X360"),
581 .callback
= dmi_check_cb
,
584 .ident
= "R410 Plus",
586 DMI_MATCH(DMI_SYS_VENDOR
,
587 "SAMSUNG ELECTRONICS CO., LTD."),
588 DMI_MATCH(DMI_PRODUCT_NAME
, "R410P"),
589 DMI_MATCH(DMI_BOARD_NAME
, "R460"),
591 .callback
= dmi_check_cb
,
596 DMI_MATCH(DMI_SYS_VENDOR
,
597 "SAMSUNG ELECTRONICS CO., LTD."),
598 DMI_MATCH(DMI_PRODUCT_NAME
, "R518"),
599 DMI_MATCH(DMI_BOARD_NAME
, "R518"),
601 .callback
= dmi_check_cb
,
604 .ident
= "R519/R719",
606 DMI_MATCH(DMI_SYS_VENDOR
,
607 "SAMSUNG ELECTRONICS CO., LTD."),
608 DMI_MATCH(DMI_PRODUCT_NAME
, "R519/R719"),
609 DMI_MATCH(DMI_BOARD_NAME
, "R519/R719"),
611 .callback
= dmi_check_cb
,
614 .ident
= "N150/N210/N220",
616 DMI_MATCH(DMI_SYS_VENDOR
,
617 "SAMSUNG ELECTRONICS CO., LTD."),
618 DMI_MATCH(DMI_PRODUCT_NAME
, "N150/N210/N220"),
619 DMI_MATCH(DMI_BOARD_NAME
, "N150/N210/N220"),
621 .callback
= dmi_check_cb
,
624 .ident
= "N150/N210/N220/N230",
626 DMI_MATCH(DMI_SYS_VENDOR
,
627 "SAMSUNG ELECTRONICS CO., LTD."),
628 DMI_MATCH(DMI_PRODUCT_NAME
, "N150/N210/N220/N230"),
629 DMI_MATCH(DMI_BOARD_NAME
, "N150/N210/N220/N230"),
631 .callback
= dmi_check_cb
,
634 .ident
= "N150P/N210P/N220P",
636 DMI_MATCH(DMI_SYS_VENDOR
,
637 "SAMSUNG ELECTRONICS CO., LTD."),
638 DMI_MATCH(DMI_PRODUCT_NAME
, "N150P/N210P/N220P"),
639 DMI_MATCH(DMI_BOARD_NAME
, "N150P/N210P/N220P"),
641 .callback
= dmi_check_cb
,
644 .ident
= "R530/R730",
646 DMI_MATCH(DMI_SYS_VENDOR
, "SAMSUNG ELECTRONICS CO., LTD."),
647 DMI_MATCH(DMI_PRODUCT_NAME
, "R530/R730"),
648 DMI_MATCH(DMI_BOARD_NAME
, "R530/R730"),
650 .callback
= dmi_check_cb
,
653 .ident
= "NF110/NF210/NF310",
655 DMI_MATCH(DMI_SYS_VENDOR
, "SAMSUNG ELECTRONICS CO., LTD."),
656 DMI_MATCH(DMI_PRODUCT_NAME
, "NF110/NF210/NF310"),
657 DMI_MATCH(DMI_BOARD_NAME
, "NF110/NF210/NF310"),
659 .callback
= dmi_check_cb
,
662 .ident
= "N145P/N250P/N260P",
664 DMI_MATCH(DMI_SYS_VENDOR
, "SAMSUNG ELECTRONICS CO., LTD."),
665 DMI_MATCH(DMI_PRODUCT_NAME
, "N145P/N250P/N260P"),
666 DMI_MATCH(DMI_BOARD_NAME
, "N145P/N250P/N260P"),
668 .callback
= dmi_check_cb
,
673 DMI_MATCH(DMI_SYS_VENDOR
,
674 "SAMSUNG ELECTRONICS CO., LTD."),
675 DMI_MATCH(DMI_PRODUCT_NAME
, "R70/R71"),
676 DMI_MATCH(DMI_BOARD_NAME
, "R70/R71"),
678 .callback
= dmi_check_cb
,
683 DMI_MATCH(DMI_SYS_VENDOR
, "SAMSUNG ELECTRONICS CO., LTD."),
684 DMI_MATCH(DMI_PRODUCT_NAME
, "P460"),
685 DMI_MATCH(DMI_BOARD_NAME
, "P460"),
687 .callback
= dmi_check_cb
,
691 MODULE_DEVICE_TABLE(dmi
, samsung_dmi_table
);
693 static int find_signature(void __iomem
*memcheck
, const char *testStr
)
698 for (loca
= 0; loca
< 0xffff; loca
++) {
699 char temp
= readb(memcheck
+ loca
);
701 if (temp
== testStr
[i
]) {
702 if (i
== strlen(testStr
)-1)
712 static int __init
samsung_init(void)
714 struct backlight_properties props
;
715 struct sabi_retval sretval
;
721 mutex_init(&sabi_mutex
);
723 if (!force
&& !dmi_check_system(samsung_dmi_table
))
726 f0000_segment
= ioremap_nocache(0xf0000, 0xffff);
727 if (!f0000_segment
) {
728 pr_err("Can't map the segment at 0xf0000\n");
732 /* Try to find one of the signatures in memory to find the header */
733 for (i
= 0; sabi_configs
[i
].test_string
!= 0; ++i
) {
734 sabi_config
= &sabi_configs
[i
];
735 loca
= find_signature(f0000_segment
, sabi_config
->test_string
);
740 if (loca
== 0xffff) {
741 pr_err("This computer does not support SABI\n");
742 goto error_no_signature
;
745 /* point to the SMI port Number */
747 sabi
= (f0000_segment
+ loca
);
750 printk(KERN_DEBUG
"This computer supports SABI==%x\n",
752 printk(KERN_DEBUG
"SABI header:\n");
753 printk(KERN_DEBUG
" SMI Port Number = 0x%04x\n",
754 readw(sabi
+ sabi_config
->header_offsets
.port
));
755 printk(KERN_DEBUG
" SMI Interface Function = 0x%02x\n",
756 readb(sabi
+ sabi_config
->header_offsets
.iface_func
));
757 printk(KERN_DEBUG
" SMI enable memory buffer = 0x%02x\n",
758 readb(sabi
+ sabi_config
->header_offsets
.en_mem
));
759 printk(KERN_DEBUG
" SMI restore memory buffer = 0x%02x\n",
760 readb(sabi
+ sabi_config
->header_offsets
.re_mem
));
761 printk(KERN_DEBUG
" SABI data offset = 0x%04x\n",
762 readw(sabi
+ sabi_config
->header_offsets
.data_offset
));
763 printk(KERN_DEBUG
" SABI data segment = 0x%04x\n",
764 readw(sabi
+ sabi_config
->header_offsets
.data_segment
));
767 /* Get a pointer to the SABI Interface */
768 ifaceP
= (readw(sabi
+ sabi_config
->header_offsets
.data_segment
) & 0x0ffff) << 4;
769 ifaceP
+= readw(sabi
+ sabi_config
->header_offsets
.data_offset
) & 0x0ffff;
770 sabi_iface
= ioremap_nocache(ifaceP
, 16);
772 pr_err("Can't remap %x\n", ifaceP
);
776 printk(KERN_DEBUG
"ifaceP = 0x%08x\n", ifaceP
);
777 printk(KERN_DEBUG
"sabi_iface = %p\n", sabi_iface
);
782 retval
= sabi_get_command(sabi_config
->commands
.get_brightness
,
784 printk(KERN_DEBUG
"brightness = 0x%02x\n", sretval
.retval
[0]);
787 /* Turn on "Linux" mode in the BIOS */
788 if (sabi_config
->commands
.set_linux
!= 0xff) {
789 retval
= sabi_set_command(sabi_config
->commands
.set_linux
,
792 pr_warn("Linux mode was not set!\n");
793 goto error_no_platform
;
797 /* knock up a platform device to hang stuff off of */
798 sdev
= platform_device_register_simple("samsung", -1, NULL
, 0);
800 goto error_no_platform
;
802 /* create a backlight device to talk to this one */
803 memset(&props
, 0, sizeof(struct backlight_properties
));
804 props
.type
= BACKLIGHT_PLATFORM
;
805 props
.max_brightness
= sabi_config
->max_brightness
;
806 backlight_device
= backlight_device_register("samsung", &sdev
->dev
,
807 NULL
, &backlight_ops
,
809 if (IS_ERR(backlight_device
))
810 goto error_no_backlight
;
812 backlight_device
->props
.brightness
= read_brightness();
813 backlight_device
->props
.power
= FB_BLANK_UNBLANK
;
814 backlight_update_status(backlight_device
);
816 retval
= init_wireless(sdev
);
820 retval
= device_create_file(&sdev
->dev
, &dev_attr_performance_level
);
822 goto error_file_create
;
831 backlight_device_unregister(backlight_device
);
834 platform_device_unregister(sdev
);
840 iounmap(f0000_segment
);
844 static void __exit
samsung_exit(void)
846 /* Turn off "Linux" mode in the BIOS */
847 if (sabi_config
->commands
.set_linux
!= 0xff)
848 sabi_set_command(sabi_config
->commands
.set_linux
, 0x80);
850 device_remove_file(&sdev
->dev
, &dev_attr_performance_level
);
851 backlight_device_unregister(backlight_device
);
854 iounmap(f0000_segment
);
855 platform_device_unregister(sdev
);
858 module_init(samsung_init
);
859 module_exit(samsung_exit
);
861 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
862 MODULE_DESCRIPTION("Samsung Backlight driver");
863 MODULE_LICENSE("GPL");