diff options
Diffstat (limited to 'drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c')
-rw-r--r-- | drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 147 |
1 files changed, 116 insertions, 31 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index b096b7d30463..1af9da8acf4c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 #include <linux/module.h> #include <linux/i2c.h> #include <linux/dmi.h> @@ -327,15 +328,6 @@ static struct gmin_cfg_var i8880_vars[] = { {}, }; -static struct gmin_cfg_var asus_vars[] = { - {"OVTI2680:00_CsiPort", "1"}, - {"OVTI2680:00_CsiLanes", "1"}, - {"OVTI2680:00_CsiFmt", "15"}, - {"OVTI2680:00_CsiBayer", "0"}, - {"OVTI2680:00_CamClk", "1"}, - {}, -}; - static const struct dmi_system_id gmin_vars[] = { { .ident = "BYT-T FFD8", @@ -373,13 +365,6 @@ static const struct dmi_system_id gmin_vars[] = { }, .driver_data = i8880_vars, }, - { - .ident = "T101HA", - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "T101HA"), - }, - .driver_data = asus_vars, - }, {} }; @@ -387,6 +372,10 @@ static const struct dmi_system_id gmin_vars[] = { 0xa9, 0x71, 0xe8, 0x77, \ 0x75, 0x60, 0x68, 0xf7) +static const guid_t atomisp_dsm_guid = GUID_INIT(0xdc2f6c4f, 0x045b, 0x4f1d, + 0x97, 0xb9, 0x88, 0x2a, + 0x68, 0x60, 0xa4, 0xbe); + #define CFG_VAR_NAME_MAX 64 #define GMIN_PMC_CLK_NAME 14 /* "pmc_plt_clk_[0..5]" */ @@ -454,15 +443,28 @@ static int gmin_i2c_write(struct device *dev, u16 i2c_addr, u8 reg, static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev) { - int i, ret; - struct device *dev; struct i2c_client *power = NULL, *client = v4l2_get_subdevdata(subdev); + struct acpi_device *adev; + acpi_handle handle; + struct device *dev; + int i, ret; if (!client) return NULL; dev = &client->dev; + handle = ACPI_HANDLE(dev); + + // FIXME: may need to release resources allocated by acpi_bus_get_device() + if (!handle || acpi_bus_get_device(handle, &adev)) { + dev_err(dev, "Error could not get ACPI device\n"); + return NULL; + } + + dev_info(&client->dev, "%s: ACPI detected it on bus ID=%s, HID=%s\n", + __func__, acpi_device_bid(adev), acpi_device_hid(adev)); + if (!pmic_id) { if (gmin_i2c_dev_exists(dev, PMIC_ACPI_TI, &power)) pmic_id = PMIC_TI; @@ -479,7 +481,6 @@ static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev) if (i >= MAX_SUBDEVS) return NULL; - if (power) { gmin_subdevs[i].pwm_i2c_addr = power->addr; dev_info(dev, @@ -616,6 +617,7 @@ static int axp_regulator_set(struct device *dev, struct gmin_subdev *gs, static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) { int ret; + ret = axp_regulator_set(dev, gs, gs->eldo2_sel_reg, gs->eldo2_1p8v, ELDO_CTRL_REG, gs->eldo2_ctrl_shift, true); if (ret) @@ -640,6 +642,7 @@ static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) static int axp_v1p8_off(struct device *dev, struct gmin_subdev *gs) { int ret; + ret = axp_regulator_set(dev, gs, gs->eldo1_sel_reg, gs->eldo1_1p8v, ELDO_CTRL_REG, gs->eldo1_ctrl_shift, false); if (ret) @@ -650,7 +653,6 @@ static int axp_v1p8_off(struct device *dev, struct gmin_subdev *gs) return ret; } - static int gmin_gpio0_ctrl(struct v4l2_subdev *subdev, int on) { struct gmin_subdev *gs = find_gmin_subdev(subdev); @@ -753,7 +755,6 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) dev_err(subdev->dev, "Couldn't set power mode for v1p2\n"); } - return -EINVAL; } @@ -921,7 +922,8 @@ int atomisp_gmin_register_vcm_control(struct camera_vcm_control *vcmCtrl) } EXPORT_SYMBOL_GPL(atomisp_gmin_register_vcm_control); -static int gmin_get_hardcoded_var(struct gmin_cfg_var *varlist, +static int gmin_get_hardcoded_var(struct device *dev, + struct gmin_cfg_var *varlist, const char *var8, char *out, size_t *out_len) { struct gmin_cfg_var *gv; @@ -932,11 +934,13 @@ static int gmin_get_hardcoded_var(struct gmin_cfg_var *varlist, if (strcmp(var8, gv->name)) continue; + dev_info(dev, "Found DMI entry for '%s'\n", var8); + vl = strlen(gv->val); if (vl > *out_len - 1) return -ENOSPC; - strcpy(out, gv->val); + strscpy(out, gv->val, *out_len); *out_len = vl; return 0; } @@ -944,6 +948,75 @@ static int gmin_get_hardcoded_var(struct gmin_cfg_var *varlist, return -EINVAL; } + +static int gmin_get_config_dsm_var(struct device *dev, + const char *var, + char *out, size_t *out_len) +{ + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object *obj, *cur = NULL; + int i; + + obj = acpi_evaluate_dsm(handle, &atomisp_dsm_guid, 0, 0, NULL); + if (!obj) { + dev_info_once(dev, "Didn't find ACPI _DSM table.\n"); + return -EINVAL; + } + +#if 0 /* Just for debugging purposes */ + for (i = 0; i < obj->package.count; i++) { + union acpi_object *cur = &obj->package.elements[i]; + + if (cur->type == ACPI_TYPE_INTEGER) + dev_info(dev, "object #%d, type %d, value: %lld\n", + i, cur->type, cur->integer.value); + else if (cur->type == ACPI_TYPE_STRING) + dev_info(dev, "object #%d, type %d, string: %s\n", + i, cur->type, cur->string.pointer); + else + dev_info(dev, "object #%d, type %d\n", + i, cur->type); + } +#endif + + /* Seek for the desired var */ + for (i = 0; i < obj->package.count - 1; i += 2) { + if (obj->package.elements[i].type == ACPI_TYPE_STRING && + !strcmp(obj->package.elements[i].string.pointer, var)) { + /* Next element should be the required value */ + cur = &obj->package.elements[i + 1]; + break; + } + } + + if (!cur) { + dev_info(dev, "didn't found _DSM entry for '%s'\n", var); + ACPI_FREE(obj); + return -EINVAL; + } + + /* + * While it could be possible to have an ACPI_TYPE_INTEGER, + * and read the value from cur->integer.value, the table + * seen so far uses the string type. So, produce a warning + * if it founds something different than string, letting it + * to fall back to the old code. + */ + if (cur && cur->type != ACPI_TYPE_STRING) { + dev_info(dev, "found non-string _DSM entry for '%s'\n", var); + ACPI_FREE(obj); + return -EINVAL; + } + + dev_info(dev, "found _DSM entry for '%s': %s\n", var, + cur->string.pointer); + strscpy(out, cur->string.pointer, *out_len); + *out_len = strlen(cur->string.pointer); + + ACPI_FREE(obj); + return 0; +} + /* Retrieves a device-specific configuration variable. The dev * argument should be a device with an ACPI companion, as all * configuration is based on firmware ID. @@ -953,12 +1026,21 @@ static int gmin_get_config_var(struct device *maindev, const char *var, char *out, size_t *out_len) { - char var8[CFG_VAR_NAME_MAX]; efi_char16_t var16[CFG_VAR_NAME_MAX]; - struct efivar_entry *ev; const struct dmi_system_id *id; - int i, ret; struct device *dev = maindev; + char var8[CFG_VAR_NAME_MAX]; + struct efivar_entry *ev; + int i, ret; + + /* For sensors, try first to use the _DSM table */ + if (!is_gmin) { + ret = gmin_get_config_dsm_var(maindev, var, out, out_len); + if (!ret) + return 0; + } + + /* Fall-back to other approaches */ if (!is_gmin && ACPI_COMPANION(dev)) dev = &ACPI_COMPANION(dev)->dev; @@ -977,9 +1059,10 @@ static int gmin_get_config_var(struct device *maindev, */ id = dmi_first_match(gmin_vars); if (id) { - dev_info(maindev, "Found DMI entry for '%s'\n", var8); - return gmin_get_hardcoded_var(id->driver_data, var8, out, - out_len); + ret = gmin_get_hardcoded_var(maindev, id->driver_data, var8, + out, out_len); + if (!ret) + return 0; } /* Our variable names are ASCII by construction, but EFI names @@ -1009,9 +1092,9 @@ static int gmin_get_config_var(struct device *maindev, *out_len = ev->var.DataSize; dev_info(maindev, "found EFI entry for '%s'\n", var8); } else if (is_gmin) { - dev_warn(maindev, "Failed to find gmin variable %s\n", var8); + dev_info(maindev, "Failed to find EFI gmin variable %s\n", var8); } else { - dev_warn(maindev, "Failed to find variable %s\n", var8); + dev_info(maindev, "Failed to find EFI variable %s\n", var8); } kfree(ev); @@ -1030,6 +1113,8 @@ int gmin_get_var_int(struct device *dev, bool is_gmin, const char *var, int def) if (!ret) { val[len] = 0; ret = kstrtol(val, 0, &result); + } else { + dev_info(dev, "%s: using default (%d)\n", var, def); } return ret ? def : result; |