Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: atomisp: Switch to int3472 driver sensor GPIO mapping code

Replace the duplicate code for calling the special Intel camera sensor GPIO
type _DSM (79234640-9e10-4fea-a5c1-b5aa8b19756f) and mapping GPIOs to
the sensor with a call to int3472_discrete_parse_crs() from the int3472
driver.

Besides avoiding code duplication the int3472 version of the code also
supports more features, like mapping the powerdown GPIO to a regulator on
the mt9m114 which is necessary to make the camera on the Asus T100TA work.

Signed-off-by: Hans de Goede <hansg@kernel.org>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Link: https://lore.kernel.org/r/20250507184737.154747-7-hdegoede@redhat.com
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

authored by

Hans de Goede and committed by
Mauro Carvalho Chehab
cf101966 0193cce5

+30 -228
+1
drivers/staging/media/atomisp/Kconfig
··· 12 12 config VIDEO_ATOMISP 13 13 tristate "Intel Atom Image Signal Processor Driver" 14 14 depends on VIDEO_DEV && INTEL_ATOMISP 15 + depends on INTEL_SKL_INT3472 15 16 depends on IPU_BRIDGE 16 17 depends on MEDIA_PCI_SUPPORT 17 18 depends on PMIC_OPREGION
-17
drivers/staging/media/atomisp/pci/atomisp_csi2.h
··· 19 19 #define CSI2_PAD_SOURCE 1 20 20 #define CSI2_PADS_NUM 2 21 21 22 - #define CSI2_MAX_ACPI_GPIOS 2u 23 - 24 - struct acpi_device; 25 22 struct v4l2_device; 26 23 27 24 struct atomisp_device; 28 25 struct atomisp_sub_device; 29 - 30 - struct atomisp_csi2_acpi_gpio_map { 31 - struct acpi_gpio_params params[CSI2_MAX_ACPI_GPIOS]; 32 - struct acpi_gpio_mapping mapping[CSI2_MAX_ACPI_GPIOS + 1]; 33 - }; 34 - 35 - struct atomisp_csi2_acpi_gpio_parsing_data { 36 - struct acpi_device *adev; 37 - struct atomisp_csi2_acpi_gpio_map *map; 38 - u32 settings[CSI2_MAX_ACPI_GPIOS]; 39 - unsigned int settings_count; 40 - unsigned int res_count; 41 - unsigned int map_count; 42 - }; 43 26 44 27 struct atomisp_mipi_csi2_device { 45 28 struct v4l2_subdev subdev;
+28 -211
drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c
··· 13 13 #include <linux/clk.h> 14 14 #include <linux/device.h> 15 15 #include <linux/dmi.h> 16 + #include <linux/platform_data/x86/int3472.h> 16 17 #include <linux/property.h> 17 18 18 19 #include <media/ipu-bridge.h> ··· 24 23 #include "atomisp_internal.h" 25 24 26 25 #define PMC_CLK_RATE_19_2MHZ 19200000 27 - 28 - /* 29 - * 79234640-9e10-4fea-a5c1-b5aa8b19756f 30 - * This _DSM GUID returns information about the GPIO lines mapped to a sensor. 31 - * Function number 1 returns a count of the GPIO lines that are mapped. 32 - * Subsequent functions return 32 bit ints encoding information about the GPIO. 33 - */ 34 - static const guid_t intel_sensor_gpio_info_guid = 35 - GUID_INIT(0x79234640, 0x9e10, 0x4fea, 36 - 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f); 37 - 38 - #define INTEL_GPIO_DSM_TYPE_SHIFT 0 39 - #define INTEL_GPIO_DSM_TYPE_MASK GENMASK(7, 0) 40 - #define INTEL_GPIO_DSM_PIN_SHIFT 8 41 - #define INTEL_GPIO_DSM_PIN_MASK GENMASK(15, 8) 42 - #define INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT 24 43 - #define INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK GENMASK(31, 24) 44 - 45 - #define INTEL_GPIO_DSM_TYPE(x) \ 46 - (((x) & INTEL_GPIO_DSM_TYPE_MASK) >> INTEL_GPIO_DSM_TYPE_SHIFT) 47 - #define INTEL_GPIO_DSM_PIN(x) \ 48 - (((x) & INTEL_GPIO_DSM_PIN_MASK) >> INTEL_GPIO_DSM_PIN_SHIFT) 49 - #define INTEL_GPIO_DSM_SENSOR_ON_VAL(x) \ 50 - (((x) & INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK) >> INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT) 51 - 52 - /* 53 - * 822ace8f-2814-4174-a56b-5f029fe079ee 54 - * This _DSM GUID returns a string from the sensor device, which acts as a 55 - * module identifier. 56 - */ 57 - static const guid_t intel_sensor_module_guid = 58 - GUID_INIT(0x822ace8f, 0x2814, 0x4174, 59 - 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee); 60 26 61 27 /* 62 28 * dc2f6c4f-045b-4f1d-97b9-882a6860a4be ··· 291 323 return gmin_cfg_get_int(adev, "CsiPort", port); 292 324 } 293 325 294 - /* Note this always returns 1 to continue looping so that res_count is accurate */ 295 - static int atomisp_csi2_handle_acpi_gpio_res(struct acpi_resource *ares, void *_data) 296 - { 297 - struct atomisp_csi2_acpi_gpio_parsing_data *data = _data; 298 - struct acpi_resource_gpio *agpio; 299 - const char *name; 300 - bool active_low; 301 - unsigned int i; 302 - u32 settings = 0; 303 - u16 pin; 304 - 305 - if (!acpi_gpio_get_io_resource(ares, &agpio)) 306 - return 1; /* Not a GPIO, continue the loop */ 307 - 308 - data->res_count++; 309 - 310 - pin = agpio->pin_table[0]; 311 - for (i = 0; i < data->settings_count; i++) { 312 - if (INTEL_GPIO_DSM_PIN(data->settings[i]) == pin) { 313 - settings = data->settings[i]; 314 - break; 315 - } 316 - } 317 - 318 - if (i == data->settings_count) { 319 - acpi_handle_warn(data->adev->handle, 320 - "%s: Could not find DSM GPIO settings for pin %u\n", 321 - dev_name(&data->adev->dev), pin); 322 - return 1; 323 - } 324 - 325 - switch (INTEL_GPIO_DSM_TYPE(settings)) { 326 - case 0: 327 - name = "reset-gpios"; 328 - break; 329 - case 1: 330 - name = "powerdown-gpios"; 331 - break; 332 - default: 333 - acpi_handle_warn(data->adev->handle, "%s: Unknown GPIO type 0x%02lx for pin %u\n", 334 - dev_name(&data->adev->dev), 335 - INTEL_GPIO_DSM_TYPE(settings), pin); 336 - return 1; 337 - } 338 - 339 - /* 340 - * Both reset and power-down need to be logical false when the sensor 341 - * is on (sensor should not be in reset and not be powered-down). So 342 - * when the sensor-on-value (which is the physical pin value) is high, 343 - * then the signal is active-low. 344 - */ 345 - active_low = INTEL_GPIO_DSM_SENSOR_ON_VAL(settings); 346 - 347 - i = data->map_count; 348 - if (i == CSI2_MAX_ACPI_GPIOS) 349 - return 1; 350 - 351 - /* res_count is already incremented */ 352 - data->map->params[i].crs_entry_index = data->res_count - 1; 353 - data->map->params[i].active_low = active_low; 354 - data->map->mapping[i].name = name; 355 - data->map->mapping[i].data = &data->map->params[i]; 356 - data->map->mapping[i].size = 1; 357 - data->map_count++; 358 - 359 - acpi_handle_info(data->adev->handle, "%s: %s crs %d %s pin %u active-%s\n", 360 - dev_name(&data->adev->dev), name, 361 - data->res_count - 1, agpio->resource_source.string_ptr, 362 - pin, active_low ? "low" : "high"); 363 - 364 - return 1; 365 - } 366 - 367 326 /* 368 - * Helper function to create an ACPI GPIO lookup table for sensor reset and 369 - * powerdown signals on Intel Bay Trail (BYT) and Cherry Trail (CHT) devices, 370 - * including setting the correct polarity for the GPIO. 327 + * Alloc and fill an int3472_discrete_device struct so that we can re-use 328 + * the INT3472 sensor GPIO mapping code. 371 329 * 372 - * This uses the "79234640-9e10-4fea-a5c1-b5aa8b19756f" DSM method directly 373 - * on the sensor device's ACPI node. This is different from later Intel 374 - * hardware which has a separate INT3472 acpi_device with this info. 375 - * 376 - * This function must be called before creating the sw-noded describing 377 - * the fwnode graph endpoint. And sensor drivers used on these devices 378 - * must return -EPROBE_DEFER when there is no endpoint description yet. 379 - * Together this guarantees that the GPIO lookups are in place before 380 - * the sensor driver tries to get GPIOs with gpiod_get(). 381 - * 382 - * Note this code uses the same DSM GUID as the int3472_gpio_guid in 383 - * the INT3472 discrete.c code and there is some overlap, but there are 384 - * enough differences that it is difficult to share the code. 330 + * This gets called from ipu_bridge_init() which runs only once per boot, 331 + * the created faux int3472 device is leaked on purpose to keep the created 332 + * GPIO mappings around permanently. 385 333 */ 386 334 static int atomisp_csi2_add_gpio_mappings(struct acpi_device *adev) 387 335 { 388 - struct atomisp_csi2_acpi_gpio_parsing_data data = { }; 389 - LIST_HEAD(resource_list); 390 - union acpi_object *obj; 391 - unsigned int i, j; 336 + struct int3472_discrete_device *int3472; 392 337 int ret; 393 338 394 - obj = acpi_evaluate_dsm_typed(adev->handle, &intel_sensor_module_guid, 395 - 0x00, 1, NULL, ACPI_TYPE_STRING); 396 - if (obj) { 397 - acpi_handle_info(adev->handle, "%s: Sensor module id: '%s'\n", 398 - dev_name(&adev->dev), obj->string.pointer); 399 - ACPI_FREE(obj); 400 - } 401 - 402 - /* 403 - * First get the GPIO-settings count and then get count GPIO-settings 404 - * values. Note the order of these may differ from the order in which 405 - * the GPIOs are listed on the ACPI resources! So we first store them all 406 - * and then enumerate the ACPI resources and match them up by pin number. 407 - */ 408 - obj = acpi_evaluate_dsm_typed(adev->handle, 409 - &intel_sensor_gpio_info_guid, 0x00, 1, 410 - NULL, ACPI_TYPE_INTEGER); 411 - if (!obj) { 412 - acpi_handle_err(adev->handle, "%s: No _DSM entry for GPIO pin count\n", 413 - dev_name(&adev->dev)); 414 - return -EIO; 415 - } 416 - 417 - data.settings_count = obj->integer.value; 418 - ACPI_FREE(obj); 419 - 420 - if (data.settings_count > CSI2_MAX_ACPI_GPIOS) { 421 - acpi_handle_err(adev->handle, "%s: Too many GPIOs %u > %u\n", 422 - dev_name(&adev->dev), data.settings_count, 423 - CSI2_MAX_ACPI_GPIOS); 424 - return -EOVERFLOW; 425 - } 426 - 427 - for (i = 0; i < data.settings_count; i++) { 428 - /* 429 - * i + 2 because the index of this _DSM function is 1-based 430 - * and the first function is just a count. 431 - */ 432 - obj = acpi_evaluate_dsm_typed(adev->handle, 433 - &intel_sensor_gpio_info_guid, 434 - 0x00, i + 2, 435 - NULL, ACPI_TYPE_INTEGER); 436 - if (!obj) { 437 - acpi_handle_err(adev->handle, "%s: No _DSM entry for pin %u\n", 438 - dev_name(&adev->dev), i); 439 - return -EIO; 440 - } 441 - 442 - data.settings[i] = obj->integer.value; 443 - ACPI_FREE(obj); 444 - } 445 - 446 - /* Since we match up by pin-number the pin-numbers must be unique */ 447 - for (i = 0; i < data.settings_count; i++) { 448 - for (j = i + 1; j < data.settings_count; j++) { 449 - if (INTEL_GPIO_DSM_PIN(data.settings[i]) != 450 - INTEL_GPIO_DSM_PIN(data.settings[j])) 451 - continue; 452 - 453 - acpi_handle_err(adev->handle, "%s: Duplicate pin number %lu\n", 454 - dev_name(&adev->dev), 455 - INTEL_GPIO_DSM_PIN(data.settings[i])); 456 - return -EIO; 457 - } 458 - } 459 - 460 - data.map = kzalloc(sizeof(*data.map), GFP_KERNEL); 461 - if (!data.map) 339 + /* Max num GPIOs we've seen plus a terminator */ 340 + int3472 = kzalloc(struct_size(int3472, gpios.table, INT3472_MAX_SENSOR_GPIOS + 1), 341 + GFP_KERNEL); 342 + if (!int3472) 462 343 return -ENOMEM; 463 344 464 - /* Now parse the ACPI resources and build the lookup table */ 465 - data.adev = adev; 466 - ret = acpi_dev_get_resources(adev, &resource_list, 467 - atomisp_csi2_handle_acpi_gpio_res, &data); 468 - if (ret < 0) 469 - return ret; 345 + /* 346 + * On atomisp the _DSM to get the GPIO type must be made on the sensor 347 + * adev, rather than on a separate INT3472 adev. 348 + */ 349 + int3472->adev = adev; 350 + int3472->dev = &adev->dev; 351 + int3472->sensor = adev; 470 352 471 - acpi_dev_free_resource_list(&resource_list); 353 + int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev)); 354 + if (!int3472->sensor_name) { 355 + kfree(int3472); 356 + return -ENOMEM; 357 + } 472 358 473 - if (data.map_count != data.settings_count || 474 - data.res_count != data.settings_count) 475 - acpi_handle_warn(adev->handle, "%s: ACPI GPIO resources vs DSM GPIO-info count mismatch (dsm: %d res: %d map %d\n", 476 - dev_name(&adev->dev), data.settings_count, 477 - data.res_count, data.map_count); 478 - 479 - ret = acpi_dev_add_driver_gpios(adev, data.map->mapping); 480 - if (ret) 481 - acpi_handle_err(adev->handle, "%s: Error adding driver GPIOs: %d\n", 482 - dev_name(&adev->dev), ret); 359 + ret = int3472_discrete_parse_crs(int3472); 360 + if (ret) { 361 + int3472_discrete_cleanup(int3472); 362 + kfree(int3472); 363 + } 483 364 484 365 return ret; 485 366 }
+1
drivers/staging/media/atomisp/pci/atomisp_v4l2.c
··· 1513 1513 MODULE_LICENSE("GPL"); 1514 1514 MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); 1515 1515 MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); 1516 + MODULE_IMPORT_NS("INTEL_INT3472_DISCRETE");