ACPI: Allow drivers to match using Device Tree compatible property
We have lots of existing Device Tree enabled drivers and allocating separate _HID for each is not feasible. Instead we allocate special _HID "PRP0001" that means that the match should be done using Device Tree compatible property using driver's .of_match_table instead if the driver is missing .acpi_match_table. If there is a need to distinguish from where the device is enumerated (DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev). Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
b31384fa5d
commit
733e625139
@ -76,6 +76,42 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void acpi_init_of_compatible(struct acpi_device *adev)
|
||||||
|
{
|
||||||
|
const union acpi_object *of_compatible;
|
||||||
|
struct acpi_hardware_id *hwid;
|
||||||
|
bool acpi_of = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the special PRP0001 ACPI ID is present and in that
|
||||||
|
* case we fill in Device Tree compatible properties for this
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(hwid, &adev->pnp.ids, list) {
|
||||||
|
if (!strcmp(hwid->id, "PRP0001")) {
|
||||||
|
acpi_of = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acpi_of)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
|
||||||
|
&of_compatible);
|
||||||
|
if (ret) {
|
||||||
|
ret = acpi_dev_get_property(adev, "compatible",
|
||||||
|
ACPI_TYPE_STRING, &of_compatible);
|
||||||
|
if (ret) {
|
||||||
|
acpi_handle_warn(adev->handle,
|
||||||
|
"PRP0001 requires compatible property\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adev->data.of_compatible = of_compatible;
|
||||||
|
}
|
||||||
|
|
||||||
void acpi_init_properties(struct acpi_device *adev)
|
void acpi_init_properties(struct acpi_device *adev)
|
||||||
{
|
{
|
||||||
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
||||||
@ -119,6 +155,8 @@ void acpi_init_properties(struct acpi_device *adev)
|
|||||||
|
|
||||||
adev->data.pointer = buf.pointer;
|
adev->data.pointer = buf.pointer;
|
||||||
adev->data.properties = properties;
|
adev->data.properties = properties;
|
||||||
|
|
||||||
|
acpi_init_of_compatible(adev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +168,7 @@ void acpi_init_properties(struct acpi_device *adev)
|
|||||||
void acpi_free_properties(struct acpi_device *adev)
|
void acpi_free_properties(struct acpi_device *adev)
|
||||||
{
|
{
|
||||||
ACPI_FREE((void *)adev->data.pointer);
|
ACPI_FREE((void *)adev->data.pointer);
|
||||||
|
adev->data.of_compatible = NULL;
|
||||||
adev->data.pointer = NULL;
|
adev->data.pointer = NULL;
|
||||||
adev->data.properties = NULL;
|
adev->data.properties = NULL;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,44 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
|
|||||||
if (list_empty(&acpi_dev->pnp.ids))
|
if (list_empty(&acpi_dev->pnp.ids))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device has PRP0001 we expose DT compatible modalias
|
||||||
|
* instead in form of of:NnameTCcompatible.
|
||||||
|
*/
|
||||||
|
if (acpi_dev->data.of_compatible) {
|
||||||
|
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
|
||||||
|
const union acpi_object *of_compatible, *obj;
|
||||||
|
int i, nval;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
|
||||||
|
/* DT strings are all in lower case */
|
||||||
|
for (c = buf.pointer; *c != '\0'; c++)
|
||||||
|
*c = tolower(*c);
|
||||||
|
|
||||||
|
len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
|
||||||
|
ACPI_FREE(buf.pointer);
|
||||||
|
|
||||||
|
of_compatible = acpi_dev->data.of_compatible;
|
||||||
|
if (of_compatible->type == ACPI_TYPE_PACKAGE) {
|
||||||
|
nval = of_compatible->package.count;
|
||||||
|
obj = of_compatible->package.elements;
|
||||||
|
} else { /* Must be ACPI_TYPE_STRING. */
|
||||||
|
nval = 1;
|
||||||
|
obj = of_compatible;
|
||||||
|
}
|
||||||
|
for (i = 0; i < nval; i++, obj++) {
|
||||||
|
count = snprintf(&modalias[len], size, "C%s",
|
||||||
|
obj->string.pointer);
|
||||||
|
if (count < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
if (count >= size)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
len += count;
|
||||||
|
size -= count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
len = snprintf(modalias, size, "acpi:");
|
len = snprintf(modalias, size, "acpi:");
|
||||||
size -= len;
|
size -= len;
|
||||||
|
|
||||||
@ -136,6 +174,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
|
|||||||
len += count;
|
len += count;
|
||||||
size -= count;
|
size -= count;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modalias[len] = '\0';
|
modalias[len] = '\0';
|
||||||
return len;
|
return len;
|
||||||
@ -902,6 +941,51 @@ int acpi_match_device_ids(struct acpi_device *device,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(acpi_match_device_ids);
|
EXPORT_SYMBOL(acpi_match_device_ids);
|
||||||
|
|
||||||
|
/* Performs match against special "PRP0001" shoehorn ACPI ID */
|
||||||
|
static bool acpi_of_driver_match_device(struct device *dev,
|
||||||
|
const struct device_driver *drv)
|
||||||
|
{
|
||||||
|
const union acpi_object *of_compatible, *obj;
|
||||||
|
struct acpi_device *adev;
|
||||||
|
int i, nval;
|
||||||
|
|
||||||
|
adev = ACPI_COMPANION(dev);
|
||||||
|
if (!adev)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
of_compatible = adev->data.of_compatible;
|
||||||
|
if (!drv->of_match_table || !of_compatible)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (of_compatible->type == ACPI_TYPE_PACKAGE) {
|
||||||
|
nval = of_compatible->package.count;
|
||||||
|
obj = of_compatible->package.elements;
|
||||||
|
} else { /* Must be ACPI_TYPE_STRING. */
|
||||||
|
nval = 1;
|
||||||
|
obj = of_compatible;
|
||||||
|
}
|
||||||
|
/* Now we can look for the driver DT compatible strings */
|
||||||
|
for (i = 0; i < nval; i++, obj++) {
|
||||||
|
const struct of_device_id *id;
|
||||||
|
|
||||||
|
for (id = drv->of_match_table; id->compatible[0]; id++)
|
||||||
|
if (!strcasecmp(obj->string.pointer, id->compatible))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool acpi_driver_match_device(struct device *dev,
|
||||||
|
const struct device_driver *drv)
|
||||||
|
{
|
||||||
|
if (!drv->acpi_match_table)
|
||||||
|
return acpi_of_driver_match_device(dev, drv);
|
||||||
|
|
||||||
|
return !!acpi_match_device(drv->acpi_match_table, dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(acpi_driver_match_device);
|
||||||
|
|
||||||
static void acpi_free_power_resources_lists(struct acpi_device *device)
|
static void acpi_free_power_resources_lists(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -341,6 +341,7 @@ struct acpi_device_physical_node {
|
|||||||
struct acpi_device_data {
|
struct acpi_device_data {
|
||||||
const union acpi_object *pointer;
|
const union acpi_object *pointer;
|
||||||
const union acpi_object *properties;
|
const union acpi_object *properties;
|
||||||
|
const union acpi_object *of_compatible;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Device */
|
/* Device */
|
||||||
|
@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
|
|||||||
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
|
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
|
||||||
const struct device *dev);
|
const struct device *dev);
|
||||||
|
|
||||||
static inline bool acpi_driver_match_device(struct device *dev,
|
extern bool acpi_driver_match_device(struct device *dev,
|
||||||
const struct device_driver *drv)
|
const struct device_driver *drv);
|
||||||
{
|
|
||||||
return !!acpi_match_device(drv->acpi_match_table, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
|
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
|
||||||
int acpi_device_modalias(struct device *, char *, int);
|
int acpi_device_modalias(struct device *, char *, int);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user