Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight
[firefly-linux-kernel-4.4.55.git] / drivers / acpi / video.c
index 7fd672af33ba3feb1fb4bdb11b014c993eb4a4b6..04ea697f72bff00b94cc2d1151df53d8b5d93e1e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/backlight.h>
+#include <linux/video_output.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -169,6 +170,7 @@ struct acpi_video_device {
        struct acpi_device *dev;
        struct acpi_video_device_brightness *brightness;
        struct backlight_device *backlight;
+       struct output_device *output_dev;
 };
 
 /* bus */
@@ -272,6 +274,10 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
                                     u32 level_current, u32 event);
 static void acpi_video_switch_brightness(struct acpi_video_device *device,
                                         int event);
+static int acpi_video_device_get_state(struct acpi_video_device *device,
+                           unsigned long *state);
+static int acpi_video_output_get(struct output_device *od);
+static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
 
 /*backlight device sysfs support*/
 static int acpi_video_get_brightness(struct backlight_device *bd)
@@ -297,6 +303,28 @@ static struct backlight_ops acpi_backlight_ops = {
        .update_status  = acpi_video_set_brightness,
 };
 
+/*video output device sysfs support*/
+static int acpi_video_output_get(struct output_device *od)
+{
+       unsigned long state;
+       struct acpi_video_device *vd =
+               (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+       acpi_video_device_get_state(vd, &state);
+       return (int)state;
+}
+
+static int acpi_video_output_set(struct output_device *od)
+{
+       unsigned long state = od->request_state;
+       struct acpi_video_device *vd=
+               (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+       return acpi_video_device_set_state(vd, state);
+}
+
+static struct output_properties acpi_output_properties = {
+       .set_state = acpi_video_output_set,
+       .get_status = acpi_video_output_get,
+};
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -531,7 +559,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 
 static void acpi_video_device_find_cap(struct acpi_video_device *device)
 {
-       acpi_integer status;
        acpi_handle h_dummy1;
        int i;
        u32 max_level = 0;
@@ -565,50 +592,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                device->cap._DSS = 1;
        }
 
-       status = acpi_video_device_lcd_query_levels(device, &obj);
-
-       if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
-               int count = 0;
-               union acpi_object *o;
-
-               br = kzalloc(sizeof(*br), GFP_KERNEL);
-               if (!br) {
-                       printk(KERN_ERR "can't allocate memory\n");
-               } else {
-                       br->levels = kmalloc(obj->package.count *
-                                            sizeof *(br->levels), GFP_KERNEL);
-                       if (!br->levels)
-                               goto out;
-
-                       for (i = 0; i < obj->package.count; i++) {
-                               o = (union acpi_object *)&obj->package.
-                                   elements[i];
-                               if (o->type != ACPI_TYPE_INTEGER) {
-                                       printk(KERN_ERR PREFIX "Invalid data\n");
-                                       continue;
-                               }
-                               br->levels[count] = (u32) o->integer.value;
-                               if (br->levels[count] > max_level)
-                                       max_level = br->levels[count];
-                               count++;
-                       }
-                     out:
-                       if (count < 2) {
-                               kfree(br->levels);
-                               kfree(br);
+       if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
+
+               if (obj->package.count >= 2) {
+                       int count = 0;
+                       union acpi_object *o;
+
+                       br = kzalloc(sizeof(*br), GFP_KERNEL);
+                       if (!br) {
+                               printk(KERN_ERR "can't allocate memory\n");
                        } else {
-                               br->count = count;
-                               device->brightness = br;
-                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                                 "found %d brightness levels\n",
-                                                 count));
+                               br->levels = kmalloc(obj->package.count *
+                                                    sizeof *(br->levels), GFP_KERNEL);
+                               if (!br->levels)
+                                       goto out;
+
+                               for (i = 0; i < obj->package.count; i++) {
+                                       o = (union acpi_object *)&obj->package.
+                                           elements[i];
+                                       if (o->type != ACPI_TYPE_INTEGER) {
+                                               printk(KERN_ERR PREFIX "Invalid data\n");
+                                               continue;
+                                       }
+                                       br->levels[count] = (u32) o->integer.value;
+
+                                       if (br->levels[count] > max_level)
+                                               max_level = br->levels[count];
+                                       count++;
+                               }
+                             out:
+                               if (count < 2) {
+                                       kfree(br->levels);
+                                       kfree(br);
+                               } else {
+                                       br->count = count;
+                                       device->brightness = br;
+                                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                                         "found %d brightness levels\n",
+                                                         count));
+                               }
                        }
                }
+
+       } else {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
        }
 
        kfree(obj);
 
-       if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+       if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
                unsigned long tmp;
                static int count = 0;
                char *name;
@@ -626,6 +658,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 
                kfree(name);
        }
+       if (device->cap._DCS && device->cap._DSS){
+               static int count = 0;
+               char *name;
+               name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+               if (!name)
+                       return;
+               sprintf(name, "acpi_video%d", count++);
+               device->output_dev = video_output_register(name,
+                               NULL, device, &acpi_output_properties);
+               kfree(name);
+       }
        return;
 }
 
@@ -1669,6 +1712,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
        backlight_device_unregister(device->backlight);
+       video_output_unregister(device->output_dev);
        return 0;
 }