aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2014-10-21 07:33:56 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-11-04 15:58:21 -0500
commit733e625139fe455b4d910ac63c18c90f7cbe2d6f (patch)
tree0c67448b04c118138a66f485094fe951dfe24e84
parentb31384fa5de37a100507751dfb5c0a49d06cee67 (diff)
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>
-rw-r--r--drivers/acpi/property.c39
-rw-r--r--drivers/acpi/scan.c106
-rw-r--r--include/acpi/acpi_bus.h1
-rw-r--r--include/linux/acpi.h8
4 files changed, 137 insertions, 17 deletions
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 2541b1fd1fa5..27add91bc270 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -76,6 +76,42 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
76 return true; 76 return true;
77} 77}
78 78
79static void acpi_init_of_compatible(struct acpi_device *adev)
80{
81 const union acpi_object *of_compatible;
82 struct acpi_hardware_id *hwid;
83 bool acpi_of = false;
84 int ret;
85
86 /*
87 * Check if the special PRP0001 ACPI ID is present and in that
88 * case we fill in Device Tree compatible properties for this
89 * device.
90 */
91 list_for_each_entry(hwid, &adev->pnp.ids, list) {
92 if (!strcmp(hwid->id, "PRP0001")) {
93 acpi_of = true;
94 break;
95 }
96 }
97
98 if (!acpi_of)
99 return;
100
101 ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
102 &of_compatible);
103 if (ret) {
104 ret = acpi_dev_get_property(adev, "compatible",
105 ACPI_TYPE_STRING, &of_compatible);
106 if (ret) {
107 acpi_handle_warn(adev->handle,
108 "PRP0001 requires compatible property\n");
109 return;
110 }
111 }
112 adev->data.of_compatible = of_compatible;
113}
114
79void acpi_init_properties(struct acpi_device *adev) 115void acpi_init_properties(struct acpi_device *adev)
80{ 116{
81 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; 117 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
@@ -119,6 +155,8 @@ void acpi_init_properties(struct acpi_device *adev)
119 155
120 adev->data.pointer = buf.pointer; 156 adev->data.pointer = buf.pointer;
121 adev->data.properties = properties; 157 adev->data.properties = properties;
158
159 acpi_init_of_compatible(adev);
122 return; 160 return;
123 } 161 }
124 162
@@ -130,6 +168,7 @@ void acpi_init_properties(struct acpi_device *adev)
130void acpi_free_properties(struct acpi_device *adev) 168void acpi_free_properties(struct acpi_device *adev)
131{ 169{
132 ACPI_FREE((void *)adev->data.pointer); 170 ACPI_FREE((void *)adev->data.pointer);
171 adev->data.of_compatible = NULL;
133 adev->data.pointer = NULL; 172 adev->data.pointer = NULL;
134 adev->data.properties = NULL; 173 adev->data.properties = NULL;
135} 174}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 40d80ac0552f..3a8f66444532 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -124,17 +124,56 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
124 if (list_empty(&acpi_dev->pnp.ids)) 124 if (list_empty(&acpi_dev->pnp.ids))
125 return 0; 125 return 0;
126 126
127 len = snprintf(modalias, size, "acpi:"); 127 /*
128 size -= len; 128 * If the device has PRP0001 we expose DT compatible modalias
129 129 * instead in form of of:NnameTCcompatible.
130 list_for_each_entry(id, &acpi_dev->pnp.ids, list) { 130 */
131 count = snprintf(&modalias[len], size, "%s:", id->id); 131 if (acpi_dev->data.of_compatible) {
132 if (count < 0) 132 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
133 return -EINVAL; 133 const union acpi_object *of_compatible, *obj;
134 if (count >= size) 134 int i, nval;
135 return -ENOMEM; 135 char *c;
136 len += count; 136
137 size -= count; 137 acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
138 /* DT strings are all in lower case */
139 for (c = buf.pointer; *c != '\0'; c++)
140 *c = tolower(*c);
141
142 len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
143 ACPI_FREE(buf.pointer);
144
145 of_compatible = acpi_dev->data.of_compatible;
146 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
147 nval = of_compatible->package.count;
148 obj = of_compatible->package.elements;
149 } else { /* Must be ACPI_TYPE_STRING. */
150 nval = 1;
151 obj = of_compatible;
152 }
153 for (i = 0; i < nval; i++, obj++) {
154 count = snprintf(&modalias[len], size, "C%s",
155 obj->string.pointer);
156 if (count < 0)
157 return -EINVAL;
158 if (count >= size)
159 return -ENOMEM;
160
161 len += count;
162 size -= count;
163 }
164 } else {
165 len = snprintf(modalias, size, "acpi:");
166 size -= len;
167
168 list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
169 count = snprintf(&modalias[len], size, "%s:", id->id);
170 if (count < 0)
171 return -EINVAL;
172 if (count >= size)
173 return -ENOMEM;
174 len += count;
175 size -= count;
176 }
138 } 177 }
139 178
140 modalias[len] = '\0'; 179 modalias[len] = '\0';
@@ -902,6 +941,51 @@ int acpi_match_device_ids(struct acpi_device *device,
902} 941}
903EXPORT_SYMBOL(acpi_match_device_ids); 942EXPORT_SYMBOL(acpi_match_device_ids);
904 943
944/* Performs match against special "PRP0001" shoehorn ACPI ID */
945static bool acpi_of_driver_match_device(struct device *dev,
946 const struct device_driver *drv)
947{
948 const union acpi_object *of_compatible, *obj;
949 struct acpi_device *adev;
950 int i, nval;
951
952 adev = ACPI_COMPANION(dev);
953 if (!adev)
954 return false;
955
956 of_compatible = adev->data.of_compatible;
957 if (!drv->of_match_table || !of_compatible)
958 return false;
959
960 if (of_compatible->type == ACPI_TYPE_PACKAGE) {
961 nval = of_compatible->package.count;
962 obj = of_compatible->package.elements;
963 } else { /* Must be ACPI_TYPE_STRING. */
964 nval = 1;
965 obj = of_compatible;
966 }
967 /* Now we can look for the driver DT compatible strings */
968 for (i = 0; i < nval; i++, obj++) {
969 const struct of_device_id *id;
970
971 for (id = drv->of_match_table; id->compatible[0]; id++)
972 if (!strcasecmp(obj->string.pointer, id->compatible))
973 return true;
974 }
975
976 return false;
977}
978
979bool acpi_driver_match_device(struct device *dev,
980 const struct device_driver *drv)
981{
982 if (!drv->acpi_match_table)
983 return acpi_of_driver_match_device(dev, drv);
984
985 return !!acpi_match_device(drv->acpi_match_table, dev);
986}
987EXPORT_SYMBOL_GPL(acpi_driver_match_device);
988
905static void acpi_free_power_resources_lists(struct acpi_device *device) 989static void acpi_free_power_resources_lists(struct acpi_device *device)
906{ 990{
907 int i; 991 int i;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 475781170091..f59cbf860658 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -341,6 +341,7 @@ struct acpi_device_physical_node {
341struct acpi_device_data { 341struct acpi_device_data {
342 const union acpi_object *pointer; 342 const union acpi_object *pointer;
343 const union acpi_object *properties; 343 const union acpi_object *properties;
344 const union acpi_object *of_compatible;
344}; 345};
345 346
346/* Device */ 347/* Device */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 76d64d6a903a..38296d686c55 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
424const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, 424const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
425 const struct device *dev); 425 const struct device *dev);
426 426
427static inline bool acpi_driver_match_device(struct device *dev, 427extern bool acpi_driver_match_device(struct device *dev,
428 const struct device_driver *drv) 428 const struct device_driver *drv);
429{
430 return !!acpi_match_device(drv->acpi_match_table, dev);
431}
432
433int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); 429int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
434int acpi_device_modalias(struct device *, char *, int); 430int acpi_device_modalias(struct device *, char *, int);
435 431