Skip to content

Commit 387041c

Browse files
committed
media: atomisp: improve sensor detection code to use _DSM table
Instead of keep hardcoding device-specific tables, read them directly from the ACPI BIOS, if available. This method is know to work with Asus T101HA device. the same table is also visible on EzPad devices. So, it seems that at least some BIOSes use this method to pass data about ISP2401-connected sensors. Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 69a03e3 commit 387041c

File tree

2 files changed

+101
-47
lines changed

2 files changed

+101
-47
lines changed

drivers/staging/media/atomisp/TODO

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,7 @@ TODO
1818
This should be converted to the usual way, using V4L2 async subdev
1919
framework to wait for cameras to be probed;
2020

21-
2. Support for newer board-specific data (like Asus T101HA support) uses a
22-
DMI match table to retrieve sensor's data, using hard-coded values.
23-
It sounds feasible to retrieve those data directly from ACPI via _DSM
24-
tables (like this one, associated with CAM1 at the above mentioned
25-
hardware):
26-
27-
Name (C1CD, Buffer (0x0220){})
28-
Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method
29-
{
30-
If ((Arg0 == ToUUID ("dc2f6c4f-045b-4f1d-97b9-882a6860a4be")))
31-
{
32-
Local0 = Package (0x12)
33-
{
34-
"CamId",
35-
"ov2680",
36-
"CamType",
37-
"1",
38-
"CsiPort",
39-
"0",
40-
"CsiLanes",
41-
"1",
42-
"CsiFmt",
43-
"15",
44-
"CsiBayer",
45-
"0",
46-
"CamClk",
47-
"1",
48-
"Regulator1p8v",
49-
"0",
50-
"Regulator2p8v",
51-
"0"
52-
}
53-
Return (Local0)
54-
}
55-
56-
The code there at atomisp_gmin_platform has an EFI parser, but it
57-
assumes that the information would be stored on a different way.
58-
59-
As the Kernel has support for reading data from _DSM, via
60-
acpi_evaluate_dsm(), it sounds doable to use such infra and remove the
61-
DMI match, at least for some devices. This will likely allow covering
62-
more devices that could also be using the same EFI UUID.
21+
2. Use ACPI _DSM table - DONE!
6322

6423
3. Switch the driver to use pm_runtime stuff. Right now, it probes the
6524
existing PMIC code and sensors call it directly.

drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ static const struct dmi_system_id gmin_vars[] = {
388388
0xa9, 0x71, 0xe8, 0x77, \
389389
0x75, 0x60, 0x68, 0xf7)
390390

391+
static const guid_t atomisp_dsm_guid = GUID_INIT(0xdc2f6c4f, 0x045b, 0x4f1d,
392+
0x97, 0xb9, 0x88, 0x2a,
393+
0x68, 0x60, 0xa4, 0xbe);
394+
391395
#define CFG_VAR_NAME_MAX 64
392396

393397
#define GMIN_PMC_CLK_NAME 14 /* "pmc_plt_clk_[0..5]" */
@@ -455,15 +459,28 @@ static int gmin_i2c_write(struct device *dev, u16 i2c_addr, u8 reg,
455459

456460
static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev)
457461
{
458-
int i, ret;
459-
struct device *dev;
460462
struct i2c_client *power = NULL, *client = v4l2_get_subdevdata(subdev);
463+
struct acpi_device *adev;
464+
acpi_handle handle;
465+
struct device *dev;
466+
int i, ret;
461467

462468
if (!client)
463469
return NULL;
464470

465471
dev = &client->dev;
466472

473+
handle = ACPI_HANDLE(dev);
474+
475+
// FIXME: may need to release resources allocated by acpi_bus_get_device()
476+
if (!handle || acpi_bus_get_device(handle, &adev)) {
477+
dev_err(dev, "Error could not get ACPI device\n");
478+
return NULL;
479+
}
480+
481+
dev_info(&client->dev, "%s: ACPI detected it on bus ID=%s, HID=%s\n",
482+
__func__, acpi_device_bid(adev), acpi_device_hid(adev));
483+
467484
if (!pmic_id) {
468485
if (gmin_i2c_dev_exists(dev, PMIC_ACPI_TI, &power))
469486
pmic_id = PMIC_TI;
@@ -944,6 +961,75 @@ static int gmin_get_hardcoded_var(struct gmin_cfg_var *varlist,
944961
return -EINVAL;
945962
}
946963

964+
965+
static int gmin_get_config_dsm_var(struct device *dev,
966+
const char *var,
967+
char *out, size_t *out_len)
968+
{
969+
acpi_handle handle = ACPI_HANDLE(dev);
970+
union acpi_object *obj, *cur = NULL;
971+
int i;
972+
973+
obj = acpi_evaluate_dsm(handle, &atomisp_dsm_guid, 0, 0, NULL);
974+
if (!obj) {
975+
dev_info_once(dev, "Didn't find ACPI _DSM table.\n");
976+
return -EINVAL;
977+
}
978+
979+
#if 0 /* Just for debugging purposes */
980+
for (i = 0; i < obj->package.count; i++) {
981+
union acpi_object *cur = &obj->package.elements[i];
982+
983+
if (cur->type == ACPI_TYPE_INTEGER)
984+
dev_info(dev, "object #%d, type %d, value: %lld\n",
985+
i, cur->type, cur->integer.value);
986+
else if (cur->type == ACPI_TYPE_STRING)
987+
dev_info(dev, "object #%d, type %d, string: %s\n",
988+
i, cur->type, cur->string.pointer);
989+
else
990+
dev_info(dev, "object #%d, type %d\n",
991+
i, cur->type);
992+
}
993+
#endif
994+
995+
/* Seek for the desired var */
996+
for (i = 0; i < obj->package.count - 1; i += 2) {
997+
if (obj->package.elements[i].type == ACPI_TYPE_STRING &&
998+
!strcmp(obj->package.elements[i].string.pointer, var)) {
999+
/* Next element should be the required value */
1000+
cur = &obj->package.elements[i + 1];
1001+
break;
1002+
}
1003+
}
1004+
1005+
if (!cur) {
1006+
dev_info(dev, "didn't found _DSM entry for '%s'\n", var);
1007+
ACPI_FREE(obj);
1008+
return -EINVAL;
1009+
}
1010+
1011+
/*
1012+
* While it could be possible to have an ACPI_TYPE_INTEGER,
1013+
* and read the value from cur->integer.value, the table
1014+
* seen so far uses the string type. So, produce a warning
1015+
* if it founds something different than string, letting it
1016+
* to fall back to the old code.
1017+
*/
1018+
if (cur && cur->type != ACPI_TYPE_STRING) {
1019+
dev_info(dev, "found non-string _DSM entry for '%s'\n", var);
1020+
ACPI_FREE(obj);
1021+
return -EINVAL;
1022+
}
1023+
1024+
dev_info(dev, "found _DSM entry for '%s': %s\n", var,
1025+
cur->string.pointer);
1026+
strscpy(out, cur->string.pointer, *out_len);
1027+
*out_len = strlen(cur->string.pointer);
1028+
1029+
ACPI_FREE(obj);
1030+
return 0;
1031+
}
1032+
9471033
/* Retrieves a device-specific configuration variable. The dev
9481034
* argument should be a device with an ACPI companion, as all
9491035
* configuration is based on firmware ID.
@@ -953,12 +1039,21 @@ static int gmin_get_config_var(struct device *maindev,
9531039
const char *var,
9541040
char *out, size_t *out_len)
9551041
{
956-
char var8[CFG_VAR_NAME_MAX];
9571042
efi_char16_t var16[CFG_VAR_NAME_MAX];
958-
struct efivar_entry *ev;
9591043
const struct dmi_system_id *id;
960-
int i, ret;
9611044
struct device *dev = maindev;
1045+
char var8[CFG_VAR_NAME_MAX];
1046+
struct efivar_entry *ev;
1047+
int i, ret;
1048+
1049+
/* For sensors, try first to use the _DSM table */
1050+
if (!is_gmin) {
1051+
ret = gmin_get_config_dsm_var(maindev, var, out, out_len);
1052+
if (!ret)
1053+
return 0;
1054+
}
1055+
1056+
/* Fall-back to other approaches */
9621057

9631058
if (!is_gmin && ACPI_COMPANION(dev))
9641059
dev = &ACPI_COMPANION(dev)->dev;

0 commit comments

Comments
 (0)