Commit 52e70c8a authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'acpi-power', 'acpi-blacklist', 'acpi-video' and 'acpi-doc'

* acpi-power:
  power: supply: axp288_charger: Only wait for INT3496 device if present
  ACPI / AC: Add a blacklist with PMIC ACPI HIDs with a native charger driver
  ACPI / battery: Add a blacklist with PMIC ACPI HIDs with a native battery driver
  ACPI / battery: Fix acpi_battery_exit on acpi_battery_init_async errors
  ACPI / utils: Add new acpi_dev_present helper

* acpi-blacklist:
  ACPI / blacklist: add _REV quirk for Dell Inspiron 7537

* acpi-video:
  ACPI / video: add comments about subtle cases
  ACPI / video: get rid of magic numbers and use enum instead

* acpi-doc:
  ACPI / doc: linuxized-acpica.txt: fix typos
...@@ -24,7 +24,7 @@ upstream. ...@@ -24,7 +24,7 @@ upstream.
The homepage of ACPICA project is: www.acpica.org, it is maintained and The homepage of ACPICA project is: www.acpica.org, it is maintained and
supported by Intel Corporation. supported by Intel Corporation.
The following figure depicts the Linux ACPI subystem where the ACPICA The following figure depicts the Linux ACPI subsystem where the ACPICA
adaptation is included: adaptation is included:
+---------------------------------------------------------+ +---------------------------------------------------------+
...@@ -110,7 +110,7 @@ upstream. ...@@ -110,7 +110,7 @@ upstream.
Linux patches. The patches generated by this process are referred to as Linux patches. The patches generated by this process are referred to as
"linuxized ACPICA patches". The release process is carried out on a local "linuxized ACPICA patches". The release process is carried out on a local
copy the ACPICA git repository. Each commit in the monthly release is copy the ACPICA git repository. Each commit in the monthly release is
converted into a linuxized ACPICA patch. Together, they form the montly converted into a linuxized ACPICA patch. Together, they form the monthly
ACPICA release patchset for the Linux ACPI community. This process is ACPICA release patchset for the Linux ACPI community. This process is
illustrated in the following figure: illustrated in the following figure:
...@@ -165,7 +165,7 @@ upstream. ...@@ -165,7 +165,7 @@ upstream.
<http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git>. <http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git>.
Before the linuxized ACPICA patches are sent to the Linux ACPI community Before the linuxized ACPICA patches are sent to the Linux ACPI community
for review, there is a quality ensurance build test process to reduce for review, there is a quality assurance build test process to reduce
porting issues. Currently this build process only takes care of the porting issues. Currently this build process only takes care of the
following kernel configuration options: following kernel configuration options:
CONFIG_ACPI/CONFIG_ACPI_DEBUG/CONFIG_ACPI_DEBUGGER CONFIG_ACPI/CONFIG_ACPI_DEBUG/CONFIG_ACPI_DEBUGGER
...@@ -195,12 +195,12 @@ upstream. ...@@ -195,12 +195,12 @@ upstream.
release utilities (please refer to Section 4 below for the details). release utilities (please refer to Section 4 below for the details).
3. Linux specific features - Sometimes it's impossible to use the 3. Linux specific features - Sometimes it's impossible to use the
current ACPICA APIs to implement features required by the Linux kernel, current ACPICA APIs to implement features required by the Linux kernel,
so Linux developers occasionaly have to change ACPICA code directly. so Linux developers occasionally have to change ACPICA code directly.
Those changes may not be acceptable by ACPICA upstream and in such cases Those changes may not be acceptable by ACPICA upstream and in such cases
they are left as committed ACPICA divergences unless the ACPICA side can they are left as committed ACPICA divergences unless the ACPICA side can
implement new mechanisms as replacements for them. implement new mechanisms as replacements for them.
4. ACPICA release fixups - ACPICA only tests commits using a set of the 4. ACPICA release fixups - ACPICA only tests commits using a set of the
user space simulation utilies, thus the linuxized ACPICA patches may user space simulation utilities, thus the linuxized ACPICA patches may
break the Linux kernel, leaving us build/boot failures. In order to break the Linux kernel, leaving us build/boot failures. In order to
avoid breaking Linux bisection, fixes are applied directly to the avoid breaking Linux bisection, fixes are applied directly to the
linuxized ACPICA patches during the release process. When the release linuxized ACPICA patches during the release process. When the release
......
...@@ -57,12 +57,23 @@ static int acpi_ac_add(struct acpi_device *device); ...@@ -57,12 +57,23 @@ static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device); static int acpi_ac_remove(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event); static void acpi_ac_notify(struct acpi_device *device, u32 event);
struct acpi_ac_bl {
const char *hid;
int hrv;
};
static const struct acpi_device_id ac_device_ids[] = { static const struct acpi_device_id ac_device_ids[] = {
{"ACPI0003", 0}, {"ACPI0003", 0},
{"", 0}, {"", 0},
}; };
MODULE_DEVICE_TABLE(acpi, ac_device_ids); MODULE_DEVICE_TABLE(acpi, ac_device_ids);
/* Lists of PMIC ACPI HIDs with an (often better) native charger driver */
static const struct acpi_ac_bl acpi_ac_blacklist[] = {
{ "INT33F4", -1 }, /* X-Powers AXP288 PMIC */
{ "INT34D3", 3 }, /* Intel Cherrytrail Whiskey Cove PMIC */
};
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int acpi_ac_resume(struct device *dev); static int acpi_ac_resume(struct device *dev);
#endif #endif
...@@ -424,11 +435,20 @@ static int acpi_ac_remove(struct acpi_device *device) ...@@ -424,11 +435,20 @@ static int acpi_ac_remove(struct acpi_device *device)
static int __init acpi_ac_init(void) static int __init acpi_ac_init(void)
{ {
unsigned int i;
int result; int result;
if (acpi_disabled) if (acpi_disabled)
return -ENODEV; return -ENODEV;
for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++)
if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1",
acpi_ac_blacklist[i].hrv)) {
pr_info(PREFIX "AC: found native %s PMIC, not loading\n",
acpi_ac_blacklist[i].hid);
return -ENODEV;
}
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
acpi_ac_dir = acpi_lock_ac_dir(); acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir) if (!acpi_ac_dir)
......
...@@ -73,6 +73,10 @@ module_param(report_key_events, int, 0644); ...@@ -73,6 +73,10 @@ module_param(report_key_events, int, 0644);
MODULE_PARM_DESC(report_key_events, MODULE_PARM_DESC(report_key_events,
"0: none, 1: output changes, 2: brightness changes, 3: all"); "0: none, 1: output changes, 2: brightness changes, 3: all");
/*
* Whether the struct acpi_video_device_attrib::device_id_scheme bit should be
* assumed even if not actually set.
*/
static bool device_id_scheme = false; static bool device_id_scheme = false;
module_param(device_id_scheme, bool, 0444); module_param(device_id_scheme, bool, 0444);
...@@ -88,6 +92,18 @@ static int acpi_video_bus_remove(struct acpi_device *device); ...@@ -88,6 +92,18 @@ static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event); static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
void acpi_video_detect_exit(void); void acpi_video_detect_exit(void);
/*
* Indices in the _BCL method response: the first two items are special,
* the rest are all supported levels.
*
* See page 575 of the ACPI spec 3.0
*/
enum acpi_video_level_idx {
ACPI_VIDEO_AC_LEVEL, /* level when machine has full power */
ACPI_VIDEO_BATTERY_LEVEL, /* level when machine is on batteries */
ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */
};
static const struct acpi_device_id video_device_ids[] = { static const struct acpi_device_id video_device_ids[] = {
{ACPI_VIDEO_HID, 0}, {ACPI_VIDEO_HID, 0},
{"", 0}, {"", 0},
...@@ -132,7 +148,15 @@ struct acpi_video_device_attrib { ...@@ -132,7 +148,15 @@ struct acpi_video_device_attrib {
the VGA device. */ the VGA device. */
u32 pipe_id:3; /* For VGA multiple-head devices. */ u32 pipe_id:3; /* For VGA multiple-head devices. */
u32 reserved:10; /* Must be 0 */ u32 reserved:10; /* Must be 0 */
u32 device_id_scheme:1; /* Device ID Scheme */
/*
* The device ID might not actually follow the scheme described by this
* struct acpi_video_device_attrib. If it does, then this bit
* device_id_scheme is set; otherwise, other fields should be ignored.
*
* (but also see the global flag device_id_scheme)
*/
u32 device_id_scheme:1;
}; };
struct acpi_video_enumerated_device { struct acpi_video_enumerated_device {
...@@ -217,20 +241,16 @@ static int acpi_video_get_brightness(struct backlight_device *bd) ...@@ -217,20 +241,16 @@ static int acpi_video_get_brightness(struct backlight_device *bd)
if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false)) if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
return -EINVAL; return -EINVAL;
for (i = 2; i < vd->brightness->count; i++) { for (i = ACPI_VIDEO_FIRST_LEVEL; i < vd->brightness->count; i++) {
if (vd->brightness->levels[i] == cur_level) if (vd->brightness->levels[i] == cur_level)
/* return i - ACPI_VIDEO_FIRST_LEVEL;
* The first two entries are special - see page 575
* of the ACPI spec 3.0
*/
return i - 2;
} }
return 0; return 0;
} }
static int acpi_video_set_brightness(struct backlight_device *bd) static int acpi_video_set_brightness(struct backlight_device *bd)
{ {
int request_level = bd->props.brightness + 2; int request_level = bd->props.brightness + ACPI_VIDEO_FIRST_LEVEL;
struct acpi_video_device *vd = bl_get_data(bd); struct acpi_video_device *vd = bl_get_data(bd);
cancel_delayed_work(&vd->switch_brightness_work); cancel_delayed_work(&vd->switch_brightness_work);
...@@ -244,18 +264,18 @@ static const struct backlight_ops acpi_backlight_ops = { ...@@ -244,18 +264,18 @@ static const struct backlight_ops acpi_backlight_ops = {
}; };
/* thermal cooling device callbacks */ /* thermal cooling device callbacks */
static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned static int video_get_max_state(struct thermal_cooling_device *cooling_dev,
long *state) unsigned long *state)
{ {
struct acpi_device *device = cooling_dev->devdata; struct acpi_device *device = cooling_dev->devdata;
struct acpi_video_device *video = acpi_driver_data(device); struct acpi_video_device *video = acpi_driver_data(device);
*state = video->brightness->count - 3; *state = video->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1;
return 0; return 0;
} }
static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned static int video_get_cur_state(struct thermal_cooling_device *cooling_dev,
long *state) unsigned long *state)
{ {
struct acpi_device *device = cooling_dev->devdata; struct acpi_device *device = cooling_dev->devdata;
struct acpi_video_device *video = acpi_driver_data(device); struct acpi_video_device *video = acpi_driver_data(device);
...@@ -264,7 +284,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig ...@@ -264,7 +284,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig
if (acpi_video_device_lcd_get_level_current(video, &level, false)) if (acpi_video_device_lcd_get_level_current(video, &level, false))
return -EINVAL; return -EINVAL;
for (offset = 2; offset < video->brightness->count; offset++) for (offset = ACPI_VIDEO_FIRST_LEVEL; offset < video->brightness->count;
offset++)
if (level == video->brightness->levels[offset]) { if (level == video->brightness->levels[offset]) {
*state = video->brightness->count - offset - 1; *state = video->brightness->count - offset - 1;
return 0; return 0;
...@@ -280,7 +301,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st ...@@ -280,7 +301,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st
struct acpi_video_device *video = acpi_driver_data(device); struct acpi_video_device *video = acpi_driver_data(device);
int level; int level;
if (state >= video->brightness->count - 2) if (state >= video->brightness->count - ACPI_VIDEO_FIRST_LEVEL)
return -EINVAL; return -EINVAL;
state = video->brightness->count - state; state = video->brightness->count - state;
...@@ -345,10 +366,12 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) ...@@ -345,10 +366,12 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
} }
device->brightness->curr = level; device->brightness->curr = level;
for (state = 2; state < device->brightness->count; state++) for (state = ACPI_VIDEO_FIRST_LEVEL; state < device->brightness->count;
state++)
if (level == device->brightness->levels[state]) { if (level == device->brightness->levels[state]) {
if (device->backlight) if (device->backlight)
device->backlight->props.brightness = state - 2; device->backlight->props.brightness =
state - ACPI_VIDEO_FIRST_LEVEL;
return 0; return 0;
} }
...@@ -530,14 +553,16 @@ acpi_video_bqc_value_to_level(struct acpi_video_device *device, ...@@ -530,14 +553,16 @@ acpi_video_bqc_value_to_level(struct acpi_video_device *device,
if (device->brightness->flags._BQC_use_index) { if (device->brightness->flags._BQC_use_index) {
/* /*
* _BQC returns an index that doesn't account for * _BQC returns an index that doesn't account for the first 2
* the first 2 items with special meaning, so we need * items with special meaning (see enum acpi_video_level_idx),
* to compensate for that by offsetting ourselves * so we need to compensate for that by offsetting ourselves
*/ */
if (device->brightness->flags._BCL_reversed) if (device->brightness->flags._BCL_reversed)
bqc_value = device->brightness->count - 3 - bqc_value; bqc_value = device->brightness->count -
ACPI_VIDEO_FIRST_LEVEL - 1 - bqc_value;
level = device->brightness->levels[bqc_value + 2]; level = device->brightness->levels[bqc_value +
ACPI_VIDEO_FIRST_LEVEL];
} else { } else {
level = bqc_value; level = bqc_value;
} }
...@@ -571,7 +596,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, ...@@ -571,7 +596,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
*level = acpi_video_bqc_value_to_level(device, *level); *level = acpi_video_bqc_value_to_level(device, *level);
for (i = 2; i < device->brightness->count; i++) for (i = ACPI_VIDEO_FIRST_LEVEL;
i < device->brightness->count; i++)
if (device->brightness->levels[i] == *level) { if (device->brightness->levels[i] == *level) {
device->brightness->curr = *level; device->brightness->curr = *level;
return 0; return 0;
...@@ -714,9 +740,37 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, ...@@ -714,9 +740,37 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device,
/* /*
* Some systems always report current brightness level as maximum * Some systems always report current brightness level as maximum
* through _BQC, we need to test another value for them. * through _BQC, we need to test another value for them. However,
* there is a subtlety:
*
* If the _BCL package ordering is descending, the first level
* (br->levels[2]) is likely to be 0, and if the number of levels
* matches the number of steps, we might confuse a returned level to
* mean the index.
*
* For example:
*
* current_level = max_level = 100
* test_level = 0
* returned level = 100
*
* In this case 100 means the level, not the index, and _BCM failed.
* Still, if the _BCL package ordering is descending, the index of
* level 0 is also 100, so we assume _BQC is indexed, when it's not.
*
* This causes all _BQC calls to return bogus values causing weird
* behavior from the user's perspective. For example:
*
* xbacklight -set 10; xbacklight -set 20;
*
* would flash to 90% and then slowly down to the desired level (20).
*
* The solution is simple; test anything other than the first level
* (e.g. 1).
*/ */
test_level = current_level == max_level ? br->levels[3] : max_level; test_level = current_level == max_level
? br->levels[ACPI_VIDEO_FIRST_LEVEL + 1]
: max_level;
result = acpi_video_device_lcd_set_level(device, test_level); result = acpi_video_device_lcd_set_level(device, test_level);
if (result) if (result)
...@@ -730,8 +784,8 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, ...@@ -730,8 +784,8 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device,
/* buggy _BQC found, need to find out if it uses index */ /* buggy _BQC found, need to find out if it uses index */
if (level < br->count) { if (level < br->count) {
if (br->flags._BCL_reversed) if (br->flags._BCL_reversed)
level = br->count - 3 - level; level = br->count - ACPI_VIDEO_FIRST_LEVEL - 1 - level;
if (br->levels[level + 2] == test_level) if (br->levels[level + ACPI_VIDEO_FIRST_LEVEL] == test_level)
br->flags._BQC_use_index = 1; br->flags._BQC_use_index = 1;
} }
...@@ -761,7 +815,7 @@ int acpi_video_get_levels(struct acpi_device *device, ...@@ -761,7 +815,7 @@ int acpi_video_get_levels(struct acpi_device *device,
goto out; goto out;
} }
if (obj->package.count < 2) { if (obj->package.count < ACPI_VIDEO_FIRST_LEVEL) {
result = -EINVAL; result = -EINVAL;
goto out; goto out;
} }
...@@ -773,8 +827,13 @@ int acpi_video_get_levels(struct acpi_device *device, ...@@ -773,8 +827,13 @@ int acpi_video_get_levels(struct acpi_device *device,
goto out; goto out;
} }
br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), /*
GFP_KERNEL); * Note that we have to reserve 2 extra items (ACPI_VIDEO_FIRST_LEVEL),
* in order to account for buggy BIOS which don't export the first two
* special levels (see below)
*/
br->levels = kmalloc((obj->package.count + ACPI_VIDEO_FIRST_LEVEL) *
sizeof(*br->levels), GFP_KERNEL);
if (!br->levels) { if (!br->levels) {
result = -ENOMEM; result = -ENOMEM;
goto out_free; goto out_free;
...@@ -788,7 +847,8 @@ int acpi_video_get_levels(struct acpi_device *device, ...@@ -788,7 +847,8 @@ int acpi_video_get_levels(struct acpi_device *device,
} }
value = (u32) o->integer.value; value = (u32) o->integer.value;
/* Skip duplicate entries */ /* Skip duplicate entries */
if (count > 2 && br->levels[count - 1] == value) if (count > ACPI_VIDEO_FIRST_LEVEL
&& br->levels[count - 1] == value)
continue; continue;
br->levels[count] = value; br->levels[count] = value;
...@@ -804,26 +864,29 @@ int acpi_video_get_levels(struct acpi_device *device, ...@@ -804,26 +864,29 @@ int acpi_video_get_levels(struct acpi_device *device,
* In this case, the first two elements in _BCL packages * In this case, the first two elements in _BCL packages
* are also supported brightness levels that OS should take care of. * are also supported brightness levels that OS should take care of.
*/ */
for (i = 2; i < count; i++) { for (i = ACPI_VIDEO_FIRST_LEVEL; i < count; i++) {
if (br->levels[i] == br->levels[0]) if (br->levels[i] == br->levels[ACPI_VIDEO_AC_LEVEL])
level_ac_battery++; level_ac_battery++;
if (br->levels[i] == br->levels[1]) if (br->levels[i] == br->levels[ACPI_VIDEO_BATTERY_LEVEL])
level_ac_battery++; level_ac_battery++;
} }
if (level_ac_battery < 2) { if (level_ac_battery < ACPI_VIDEO_FIRST_LEVEL) {
level_ac_battery = 2 - level_ac_battery; level_ac_battery = ACPI_VIDEO_FIRST_LEVEL - level_ac_battery;
br->flags._BCL_no_ac_battery_levels = 1; br->flags._BCL_no_ac_battery_levels = 1;
for (i = (count - 1 + level_ac_battery); i >= 2; i--) for (i = (count - 1 + level_ac_battery);
i >= ACPI_VIDEO_FIRST_LEVEL; i--)
br->levels[i] = br->levels[i - level_ac_battery]; br->levels[i] = br->levels[i - level_ac_battery];
count += level_ac_battery; count += level_ac_battery;
} else if (level_ac_battery > 2) } else if (level_ac_battery > ACPI_VIDEO_FIRST_LEVEL)
ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package")); ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package"));
/* Check if the _BCL package is in a reversed order */ /* Check if the _BCL package is in a reversed order */
if (max_level == br->levels[2]) { if (max_level == br->levels[ACPI_VIDEO_FIRST_LEVEL]) {
br->flags._BCL_reversed = 1; br->flags._BCL_reversed = 1;
sort(&br->levels[2], count - 2, sizeof(br->levels[2]), sort(&br->levels[ACPI_VIDEO_FIRST_LEVEL],
count - ACPI_VIDEO_FIRST_LEVEL,
sizeof(br->levels[ACPI_VIDEO_FIRST_LEVEL]),
acpi_video_cmp_level, NULL); acpi_video_cmp_level, NULL);
} else if (max_level != br->levels[count - 1]) } else if (max_level != br->levels[count - 1])
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
...@@ -894,7 +957,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) ...@@ -894,7 +957,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
* level_old is invalid (no matter whether it's a level * level_old is invalid (no matter whether it's a level
* or an index). Set the backlight to max_level in this case. * or an index). Set the backlight to max_level in this case.
*/ */
for (i = 2; i < br->count; i++) for (i = ACPI_VIDEO_FIRST_LEVEL; i < br->count; i++)
if (level == br->levels[i]) if (level == br->levels[i])
break; break;
if (i == br->count || !level) if (i == br->count || !level)
...@@ -906,7 +969,8 @@ acpi_video_init_brightness(struct acpi_video_device *device) ...@@ -906,7 +969,8 @@ acpi_video_init_brightness(struct acpi_video_device *device)
goto out_free_levels; goto out_free_levels;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"found %d brightness levels\n", br->count - 2)); "found %d brightness levels\n",
br->count - ACPI_VIDEO_FIRST_LEVEL));
return 0; return 0;
out_free_levels: out_free_levels:
...@@ -1297,7 +1361,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, ...@@ -1297,7 +1361,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
max = max_below = 0; max = max_below = 0;
min = min_above = 255; min = min_above = 255;
/* Find closest level to level_current */ /* Find closest level to level_current */
for (i = 2; i < device->brightness->count; i++) { for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) {
l = device->brightness->levels[i]; l = device->brightness->levels[i];
if (abs(l - level_current) < abs(delta)) { if (abs(l - level_current) < abs(delta)) {
delta = l - level_current; delta = l - level_current;
...@@ -1307,7 +1371,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, ...@@ -1307,7 +1371,7 @@ acpi_video_get_next_level(struct acpi_video_device *device,
} }
/* Ajust level_current to closest available level */ /* Ajust level_current to closest available level */
level_current += delta; level_current += delta;
for (i = 2; i < device->brightness->count; i++) { for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) {
l = device->brightness->levels[i]; l = device->brightness->levels[i];
if (l < min) if (l < min)
min = l; min = l;
...@@ -1680,7 +1744,8 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) ...@@ -1680,7 +1744,8 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
memset(&props, 0, sizeof(struct backlight_properties)); memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_FIRMWARE; props.type = BACKLIGHT_FIRMWARE;
props.max_brightness = device->brightness->count - 3; props.max_brightness =
device->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1;
device->backlight = backlight_device_register(name, device->backlight = backlight_device_register(name,
parent, parent,
device, device,
......
...@@ -67,6 +67,7 @@ MODULE_DESCRIPTION("ACPI Battery Driver"); ...@@ -67,6 +67,7 @@ MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static async_cookie_t async_cookie; static async_cookie_t async_cookie;
static bool battery_driver_registered;
static int battery_bix_broken_package; static int battery_bix_broken_package;
static int battery_notification_delay_ms; static int battery_notification_delay_ms;
static unsigned int cache_time = 1000; static unsigned int cache_time = 1000;
...@@ -93,6 +94,11 @@ static const struct acpi_device_id battery_device_ids[] = { ...@@ -93,6 +94,11 @@ static const struct acpi_device_id battery_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, battery_device_ids); MODULE_DEVICE_TABLE(acpi, battery_device_ids);
/* Lists of PMIC ACPI HIDs with an (often better) native battery driver */
static const char * const acpi_battery_blacklist[] = {
"INT33F4", /* X-Powers AXP288 PMIC */
};
enum { enum {
ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_ALARM_PRESENT,
ACPI_BATTERY_XINFO_PRESENT, ACPI_BATTERY_XINFO_PRESENT,
...@@ -1315,8 +1321,17 @@ static struct acpi_driver acpi_battery_driver = { ...@@ -1315,8 +1321,17 @@ static struct acpi_driver acpi_battery_driver = {
static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
{ {
unsigned int i;
int result; int result;
for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++)
if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) {
pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME
": found native %s PMIC, not loading\n",
acpi_battery_blacklist[i]);
return;
}
dmi_check_system(bat_dmi_table); dmi_check_system(bat_dmi_table);
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
...@@ -1329,6 +1344,7 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) ...@@ -1329,6 +1344,7 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
if (result < 0) if (result < 0)
acpi_unlock_battery_dir(acpi_battery_dir); acpi_unlock_battery_dir(acpi_battery_dir);
#endif #endif
battery_driver_registered = (result == 0);
} }
static int __init acpi_battery_init(void) static int __init acpi_battery_init(void)
...@@ -1343,8 +1359,10 @@ static int __init acpi_battery_init(void) ...@@ -1343,8 +1359,10 @@ static int __init acpi_battery_init(void)
static void __exit acpi_battery_exit(void) static void __exit acpi_battery_exit(void)
{ {
async_synchronize_cookie(async_cookie + 1); async_synchronize_cookie(async_cookie + 1);
if (battery_driver_registered)
acpi_bus_unregister_driver(&acpi_battery_driver); acpi_bus_unregister_driver(&acpi_battery_driver);
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
if (acpi_battery_dir)
acpi_unlock_battery_dir(acpi_battery_dir); acpi_unlock_battery_dir(acpi_battery_dir);
#endif #endif
} }
......
...@@ -188,6 +188,14 @@ static struct dmi_system_id acpi_rev_dmi_table[] __initdata = { ...@@ -188,6 +188,14 @@ static struct dmi_system_id acpi_rev_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"), DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"),
}, },
}, },
{
.callback = dmi_enable_rev_override,
.ident = "DELL Inspiron 7537",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"),
},
},
#endif #endif
{} {}
}; };
......
...@@ -736,6 +736,72 @@ bool acpi_dev_found(const char *hid) ...@@ -736,6 +736,72 @@ bool acpi_dev_found(const char *hid)
} }
EXPORT_SYMBOL(acpi_dev_found); EXPORT_SYMBOL(acpi_dev_found);
struct acpi_dev_present_info {
struct acpi_device_id hid[2];
const char *uid;
s64 hrv;
};
static int acpi_dev_present_cb(struct device *dev, void *data)
{
struct acpi_device *adev = to_acpi_device(dev);
struct acpi_dev_present_info *match = data;
unsigned long long hrv;
acpi_status status;
if (acpi_match_device_ids(adev, match->hid))
return 0;
if (match->uid && (!adev->pnp.unique_id ||
strcmp(adev->pnp.unique_id, match->uid)))
return 0;
if (match->hrv == -1)
return 1;
status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv);
if (ACPI_FAILURE(status))
return 0;
return hrv == match->hrv;
}
/**
* acpi_dev_present - Detect that a given ACPI device is present
* @hid: Hardware ID of the device.
* @uid: Unique ID of the device, pass NULL to not check _UID
* @hrv: Hardware Revision of the device, pass -1 to not check _HRV
*
* Return %true if a matching device was present at the moment of invocation.
* Note that if the device is pluggable, it may since have disappeared.
*
* Note that unlike acpi_dev_found() this function checks the status
* of the device. So for devices which are present in the dsdt, but
* which are disabled (their _STA callback returns 0) this function
* will return false.
*
* For this function to work, acpi_bus_scan() must have been executed
* which happens in the subsys_initcall() subsection. Hence, do not
* call from a subsys_initcall() or earlier (use acpi_get_devices()
* instead). Calling from module_init() is fine (which is synonymous
* with device_initcall()).
*/
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
{
struct acpi_dev_present_info match = {};
struct device *dev;
strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
match.uid = uid;
match.hrv = hrv;
dev = bus_find_device(&acpi_bus_type, NULL, &match,
acpi_dev_present_cb);
return !!dev;
}
EXPORT_SYMBOL(acpi_dev_present);
/* /*
* acpi_backlight= handling, this is done here rather then in video_detect.c * acpi_backlight= handling, this is done here rather then in video_detect.c
* because __setup cannot be used in modules. * because __setup cannot be used in modules.
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/acpi.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
...@@ -113,7 +114,8 @@ ...@@ -113,7 +114,8 @@
#define ILIM_3000MA 3000 /* 3000mA */ #define ILIM_3000MA 3000 /* 3000mA */
#define AXP288_EXTCON_DEV_NAME "axp288_extcon" #define AXP288_EXTCON_DEV_NAME "axp288_extcon"
#define USB_HOST_EXTCON_DEV_NAME "INT3496:00" #define USB_HOST_EXTCON_HID "INT3496"
#define USB_HOST_EXTCON_NAME "INT3496:00"
static const unsigned int cable_ids[] = static const unsigned int cable_ids[] =
{ EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP }; { EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP };
...@@ -807,11 +809,15 @@ static int axp288_charger_probe(struct platform_device *pdev) ...@@ -807,11 +809,15 @@ static int axp288_charger_probe(struct platform_device *pdev)
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_DEV_NAME); if (acpi_dev_present(USB_HOST_EXTCON_HID, NULL, -1)) {
info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_NAME);
if (info->otg.cable == NULL) { if (info->otg.cable == NULL) {
dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n"); dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n");
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
dev_info(&pdev->dev,
"Using " USB_HOST_EXTCON_HID " extcon for usb-id\n");
}
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
mutex_init(&info->lock); mutex_init(&info->lock);
...@@ -849,6 +855,7 @@ static int axp288_charger_probe(struct platform_device *pdev) ...@@ -849,6 +855,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
/* Register for OTG notification */ /* Register for OTG notification */
INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker);
info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt;
if (info->otg.cable) {
ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable, ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable,
EXTCON_USB_HOST, &info->otg.id_nb); EXTCON_USB_HOST, &info->otg.id_nb);
if (ret) { if (ret) {
...@@ -856,6 +863,7 @@ static int axp288_charger_probe(struct platform_device *pdev) ...@@ -856,6 +863,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
return ret; return ret;
} }
schedule_work(&info->otg.work); schedule_work(&info->otg.work);
}
/* Register charger interrupts */ /* Register charger interrupts */
for (i = 0; i < CHRG_INTR_END; i++) { for (i = 0; i < CHRG_INTR_END; i++) {
......
...@@ -88,6 +88,7 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, u64 rev, u64 func, ...@@ -88,6 +88,7 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,
} }
bool acpi_dev_found(const char *hid); bool acpi_dev_found(const char *hid);
bool acpi_dev_present(const char *hid, const char *uid, s64 hrv);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
......
...@@ -607,6 +607,11 @@ static inline bool acpi_dev_found(const char *hid) ...@@ -607,6 +607,11 @@ static inline bool acpi_dev_found(const char *hid)
return false; return false;
} }
static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
{
return false;
}
static inline bool is_acpi_node(struct fwnode_handle *fwnode) static inline bool is_acpi_node(struct fwnode_handle *fwnode)
{ {
return false; return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment