diff options
| -rw-r--r-- | drivers/platform/x86/sony-laptop.c | 127 |
1 files changed, 103 insertions, 24 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 9d80ae4e6be6..6fe8cd6e23b5 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
| @@ -934,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, | |||
| 934 | /* | 934 | /* |
| 935 | * Backlight device | 935 | * Backlight device |
| 936 | */ | 936 | */ |
| 937 | struct sony_backlight_props { | ||
| 938 | struct backlight_device *dev; | ||
| 939 | int handle; | ||
| 940 | u8 offset; | ||
| 941 | u8 maxlvl; | ||
| 942 | }; | ||
| 943 | struct sony_backlight_props sony_bl_props; | ||
| 944 | |||
| 937 | static int sony_backlight_update_status(struct backlight_device *bd) | 945 | static int sony_backlight_update_status(struct backlight_device *bd) |
| 938 | { | 946 | { |
| 939 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", | 947 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", |
| @@ -954,19 +962,23 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd) | |||
| 954 | { | 962 | { |
| 955 | int result; | 963 | int result; |
| 956 | int *handle = (int *)bl_get_data(bd); | 964 | int *handle = (int *)bl_get_data(bd); |
| 965 | struct sony_backlight_props *sdev = | ||
| 966 | (struct sony_backlight_props *)bl_get_data(bd); | ||
| 957 | 967 | ||
| 958 | sony_call_snc_handle(*handle, 0x0200, &result); | 968 | sony_call_snc_handle(sdev->handle, 0x0200, &result); |
| 959 | 969 | ||
| 960 | return result & 0xff; | 970 | return (result & 0xff) - sdev->offset; |
| 961 | } | 971 | } |
| 962 | 972 | ||
| 963 | static int sony_nc_update_status_ng(struct backlight_device *bd) | 973 | static int sony_nc_update_status_ng(struct backlight_device *bd) |
| 964 | { | 974 | { |
| 965 | int value, result; | 975 | int value, result; |
| 966 | int *handle = (int *)bl_get_data(bd); | 976 | int *handle = (int *)bl_get_data(bd); |
| 977 | struct sony_backlight_props *sdev = | ||
| 978 | (struct sony_backlight_props *)bl_get_data(bd); | ||
| 967 | 979 | ||
| 968 | value = bd->props.brightness; | 980 | value = bd->props.brightness + sdev->offset; |
| 969 | if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) | 981 | if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) |
| 970 | return -EIO; | 982 | return -EIO; |
| 971 | 983 | ||
| 972 | return value; | 984 | return value; |
| @@ -982,8 +994,6 @@ static const struct backlight_ops sony_backlight_ng_ops = { | |||
| 982 | .update_status = sony_nc_update_status_ng, | 994 | .update_status = sony_nc_update_status_ng, |
| 983 | .get_brightness = sony_nc_get_brightness_ng, | 995 | .get_brightness = sony_nc_get_brightness_ng, |
| 984 | }; | 996 | }; |
| 985 | static int backlight_ng_handle; | ||
| 986 | static struct backlight_device *sony_backlight_device; | ||
| 987 | 997 | ||
| 988 | /* | 998 | /* |
| 989 | * New SNC-only Vaios event mapping to driver known keys | 999 | * New SNC-only Vaios event mapping to driver known keys |
| @@ -1550,6 +1560,75 @@ static void sony_nc_kbd_backlight_resume(void) | |||
| 1550 | &ignore); | 1560 | &ignore); |
| 1551 | } | 1561 | } |
| 1552 | 1562 | ||
| 1563 | static void sony_nc_backlight_ng_read_limits(int handle, | ||
| 1564 | struct sony_backlight_props *props) | ||
| 1565 | { | ||
| 1566 | int offset; | ||
| 1567 | acpi_status status; | ||
| 1568 | u8 brlvl, i; | ||
| 1569 | u8 min = 0xff, max = 0x00; | ||
| 1570 | struct acpi_object_list params; | ||
| 1571 | union acpi_object in_obj; | ||
| 1572 | union acpi_object *lvl_enum; | ||
| 1573 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 1574 | |||
| 1575 | props->handle = handle; | ||
| 1576 | props->offset = 0; | ||
| 1577 | props->maxlvl = 0xff; | ||
| 1578 | |||
| 1579 | offset = sony_find_snc_handle(handle); | ||
| 1580 | if (offset < 0) | ||
| 1581 | return; | ||
| 1582 | |||
| 1583 | /* try to read the boundaries from ACPI tables, if we fail the above | ||
| 1584 | * defaults should be reasonable | ||
| 1585 | */ | ||
| 1586 | params.count = 1; | ||
| 1587 | params.pointer = &in_obj; | ||
| 1588 | in_obj.type = ACPI_TYPE_INTEGER; | ||
| 1589 | in_obj.integer.value = offset; | ||
| 1590 | status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, | ||
| 1591 | &buffer); | ||
| 1592 | if (ACPI_FAILURE(status)) | ||
| 1593 | return; | ||
| 1594 | |||
| 1595 | lvl_enum = (union acpi_object *) buffer.pointer; | ||
| 1596 | if (!lvl_enum) { | ||
| 1597 | pr_err("No SN06 return object."); | ||
| 1598 | return; | ||
| 1599 | } | ||
| 1600 | if (lvl_enum->type != ACPI_TYPE_BUFFER) { | ||
| 1601 | pr_err("Invalid SN06 return object 0x%.2x\n", | ||
| 1602 | lvl_enum->type); | ||
| 1603 | goto out_invalid; | ||
| 1604 | } | ||
| 1605 | |||
| 1606 | /* the buffer lists brightness levels available, brightness levels are | ||
| 1607 | * from 0 to 8 in the array, other values are used by ALS control. | ||
| 1608 | */ | ||
| 1609 | for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { | ||
| 1610 | |||
| 1611 | brlvl = *(lvl_enum->buffer.pointer + i); | ||
| 1612 | dprintk("Brightness level: %d\n", brlvl); | ||
| 1613 | |||
| 1614 | if (!brlvl) | ||
| 1615 | break; | ||
| 1616 | |||
| 1617 | if (brlvl > max) | ||
| 1618 | max = brlvl; | ||
| 1619 | if (brlvl < min) | ||
| 1620 | min = brlvl; | ||
| 1621 | } | ||
| 1622 | props->offset = min; | ||
| 1623 | props->maxlvl = max; | ||
| 1624 | dprintk("Brightness levels: min=%d max=%d\n", props->offset, | ||
| 1625 | props->maxlvl); | ||
| 1626 | |||
| 1627 | out_invalid: | ||
| 1628 | kfree(buffer.pointer); | ||
| 1629 | return; | ||
| 1630 | } | ||
| 1631 | |||
| 1553 | static void sony_nc_backlight_setup(void) | 1632 | static void sony_nc_backlight_setup(void) |
| 1554 | { | 1633 | { |
| 1555 | acpi_handle unused; | 1634 | acpi_handle unused; |
| @@ -1558,14 +1637,14 @@ static void sony_nc_backlight_setup(void) | |||
| 1558 | struct backlight_properties props; | 1637 | struct backlight_properties props; |
| 1559 | 1638 | ||
| 1560 | if (sony_find_snc_handle(0x12f) != -1) { | 1639 | if (sony_find_snc_handle(0x12f) != -1) { |
| 1561 | backlight_ng_handle = 0x12f; | ||
| 1562 | ops = &sony_backlight_ng_ops; | 1640 | ops = &sony_backlight_ng_ops; |
| 1563 | max_brightness = 0xff; | 1641 | sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); |
| 1642 | max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; | ||
| 1564 | 1643 | ||
| 1565 | } else if (sony_find_snc_handle(0x137) != -1) { | 1644 | } else if (sony_find_snc_handle(0x137) != -1) { |
| 1566 | backlight_ng_handle = 0x137; | ||
| 1567 | ops = &sony_backlight_ng_ops; | 1645 | ops = &sony_backlight_ng_ops; |
| 1568 | max_brightness = 0xff; | 1646 | sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); |
| 1647 | max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; | ||
| 1569 | 1648 | ||
| 1570 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | 1649 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", |
| 1571 | &unused))) { | 1650 | &unused))) { |
| @@ -1578,22 +1657,22 @@ static void sony_nc_backlight_setup(void) | |||
| 1578 | memset(&props, 0, sizeof(struct backlight_properties)); | 1657 | memset(&props, 0, sizeof(struct backlight_properties)); |
| 1579 | props.type = BACKLIGHT_PLATFORM; | 1658 | props.type = BACKLIGHT_PLATFORM; |
| 1580 | props.max_brightness = max_brightness; | 1659 | props.max_brightness = max_brightness; |
| 1581 | sony_backlight_device = backlight_device_register("sony", NULL, | 1660 | sony_bl_props.dev = backlight_device_register("sony", NULL, |
| 1582 | &backlight_ng_handle, | 1661 | &sony_bl_props, |
| 1583 | ops, &props); | 1662 | ops, &props); |
| 1584 | 1663 | ||
| 1585 | if (IS_ERR(sony_backlight_device)) { | 1664 | if (IS_ERR(sony_bl_props.dev)) { |
| 1586 | pr_warning(DRV_PFX "unable to register backlight device\n"); | 1665 | pr_warn(DRV_PFX "unable to register backlight device\n"); |
| 1587 | sony_backlight_device = NULL; | 1666 | sony_bl_props.dev = NULL; |
| 1588 | } else | 1667 | } else |
| 1589 | sony_backlight_device->props.brightness = | 1668 | sony_bl_props.dev->props.brightness = |
| 1590 | ops->get_brightness(sony_backlight_device); | 1669 | ops->get_brightness(sony_bl_props.dev); |
| 1591 | } | 1670 | } |
| 1592 | 1671 | ||
| 1593 | static void sony_nc_backlight_cleanup(void) | 1672 | static void sony_nc_backlight_cleanup(void) |
| 1594 | { | 1673 | { |
| 1595 | if (sony_backlight_device) | 1674 | if (sony_bl_props.dev) |
| 1596 | backlight_device_unregister(sony_backlight_device); | 1675 | backlight_device_unregister(sony_bl_props.dev); |
| 1597 | } | 1676 | } |
| 1598 | 1677 | ||
| 1599 | static int sony_nc_add(struct acpi_device *device) | 1678 | static int sony_nc_add(struct acpi_device *device) |
| @@ -2591,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
| 2591 | mutex_lock(&spic_dev.lock); | 2670 | mutex_lock(&spic_dev.lock); |
| 2592 | switch (cmd) { | 2671 | switch (cmd) { |
| 2593 | case SONYPI_IOCGBRT: | 2672 | case SONYPI_IOCGBRT: |
| 2594 | if (sony_backlight_device == NULL) { | 2673 | if (sony_bl_props.dev == NULL) { |
| 2595 | ret = -EIO; | 2674 | ret = -EIO; |
| 2596 | break; | 2675 | break; |
| 2597 | } | 2676 | } |
| @@ -2604,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
| 2604 | ret = -EFAULT; | 2683 | ret = -EFAULT; |
| 2605 | break; | 2684 | break; |
| 2606 | case SONYPI_IOCSBRT: | 2685 | case SONYPI_IOCSBRT: |
| 2607 | if (sony_backlight_device == NULL) { | 2686 | if (sony_bl_props.dev == NULL) { |
| 2608 | ret = -EIO; | 2687 | ret = -EIO; |
| 2609 | break; | 2688 | break; |
| 2610 | } | 2689 | } |
| @@ -2618,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
| 2618 | break; | 2697 | break; |
| 2619 | } | 2698 | } |
| 2620 | /* sync the backlight device status */ | 2699 | /* sync the backlight device status */ |
| 2621 | sony_backlight_device->props.brightness = | 2700 | sony_bl_props.dev->props.brightness = |
| 2622 | sony_backlight_get_brightness(sony_backlight_device); | 2701 | sony_backlight_get_brightness(sony_bl_props.dev); |
| 2623 | break; | 2702 | break; |
| 2624 | case SONYPI_IOCGBAT1CAP: | 2703 | case SONYPI_IOCGBAT1CAP: |
| 2625 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { | 2704 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { |
