--- zzzz-none-000/linux-4.9.279/drivers/i2c/busses/i2c-designware-platdrv.c 2021-08-08 06:38:54.000000000 +0000 +++ puma7-atom-6591-750/linux-4.9.279/drivers/i2c/busses/i2c-designware-platdrv.c 2023-02-08 11:43:42.000000000 +0000 @@ -21,6 +21,10 @@ * ---------------------------------------------------------------------------- * */ +/* + * Includes Intel Corporation's changes/modifications dated: 2018. + * Changed/modified portions - Copyright (c) 2018, Intel Corporation. + */ #include #include #include @@ -41,8 +45,11 @@ #include #include #include +#include #include "i2c-designware-core.h" +#include + static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) { return clk_get_rate(dev->clk)/1000; @@ -65,6 +72,136 @@ { } }; +struct dw_i2c_acpi_handler_data { + struct acpi_connection_info info; + struct platform_device *pdev; +}; + + +int dw_i2c_acquire_ownership(void) +{ +#ifdef CONFIG_GMIN_INTEL_MID + return intel_mid_dw_i2c_acquire_ownership(); +#endif + return 0; +} +int dw_i2c_release_ownership(void) +{ +#ifdef CONFIG_GMIN_INTEL_MID + return intel_mid_dw_i2c_release_ownership(); +#endif + return 0; +} +static acpi_status +dw_i2c_acpi_space_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value64, + void *handler_context, void *region_context) +{ + struct dw_i2c_acpi_handler_data *data = handler_context; + struct acpi_connection_info *info = &data->info; + struct dw_i2c_dev *dev = platform_get_drvdata(data->pdev); + struct acpi_resource_i2c_serialbus *sb; + struct acpi_resource *ares; + u8 target; + int ret, length; + u8 *value = (u8 *)value64; + u8 *buffer; + u32 accessor_type = function >> 16; + u8 addr = (u8)address; + struct i2c_msg msgs[2]; + + + acpi_buffer_to_resource(info->connection, info->length, &ares); + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return AE_BAD_PARAMETER; + + sb = &ares->data.i2c_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) + return AE_BAD_PARAMETER; + + pr_debug("%s: Found I2C Resource type, addr %d\n", + __func__, sb->slave_address); + target = sb->slave_address; + + length = acpi_get_serial_access_length(accessor_type, info->access_length); + pr_debug("%s: access opeation region, addr 0x%x operation %d len %d\n", + __func__, addr, function, length); + + if (!value64) + return AE_BAD_PARAMETER; + + function &= ACPI_IO_MASK; + if (function == ACPI_READ) { + buffer = kzalloc(length, GFP_KERNEL); + + msgs[0].addr = target; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = &addr; + + msgs[1].addr = target; + msgs[1].flags = I2C_M_RD; + msgs[1].len = length; + msgs[1].buf = buffer; + + ret = i2c_transfer(&dev->adapter, msgs, 2); + if (ret < 0) { + pr_info("%s: i2c read failed\n", __func__); + return AE_ERROR; + } + + memcpy(value + 2, buffer, length - 2); + value[0] = value[1] = 0; + kfree(buffer); + } else if (function == ACPI_WRITE) { +// buffer = kzalloc(length - 1, GFP_KERNEL); +// +// buffer[0] = addr; +// memcpy(buffer + 1, value + 2, length - 2); +// msgs[0].addr = target; +// msgs[0].flags = 0; +// msgs[0].len = length - 1; +// msgs[0].buf = buffer; +// +// ret = i2c_transfer(&dev->adapter, msgs, 2); +// if (ret < 0) { +// pr_info("%s: i2c read failed\n", __func__); +// return AE_ERROR; +// } +// kfree(buffer); +// + } + + return AE_OK; +} + +static int dw_i2c_acpi_install_space_handler(struct platform_device *pdev) +{ + acpi_handle *handle = ACPI_HANDLE(&pdev->dev); + struct dw_i2c_acpi_handler_data *data; + acpi_status status; + + if (!handle) + return -EFAULT; + + data = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_acpi_handler_data), + GFP_KERNEL); + + if(!data) + return -ENOMEM; + + data->pdev = pdev; + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_GSBUS, + &dw_i2c_acpi_space_handler, + NULL, + data); + if (ACPI_FAILURE(status)) + return -EFAULT; + return 0; +} + + static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], u16 *hcnt, u16 *lcnt, u32 *sda_hold) { @@ -94,6 +231,9 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + acpi_status status; + acpi_handle handle = ACPI_HANDLE(&pdev->dev); + unsigned long long shared_host = 0; const struct acpi_device_id *id; dev->adapter.nr = -1; @@ -114,6 +254,20 @@ if (id && id->driver_data) dev->accessor_flags |= (u32)id->driver_data; + status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); + + if (ACPI_SUCCESS(status)) + dev_info(&pdev->dev, "_SEM=%llu\n", shared_host); + + if (shared_host != 0) { + dev_info(&pdev->dev, "Share controller with PUNIT\n"); + dev->shared_host = 1; + dev->polling = 1; + dev->acquire_ownership = dw_i2c_acquire_ownership; + dev->release_ownership = dw_i2c_release_ownership; + dev->pm_runtime_disabled = 1; + } + return 0; } @@ -124,6 +278,7 @@ { "INT3433", 0 }, { "80860F41", 0 }, { "808622C1", 0 }, + { "80862BC1", 0 }, { "AMD0010", ACCESS_INTR_MASK }, { "AMDI0010", ACCESS_INTR_MASK }, { "AMDI0510", 0 }, @@ -236,7 +391,7 @@ dev->master_cfg |= DW_IC_CON_SPEED_FAST; } - dev->clk = devm_clk_get(&pdev->dev, NULL); + dev->clk = devm_clk_get(&pdev->dev, "baudclk"); if (!i2c_dw_plat_prepare_clk(dev, true)) { dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; @@ -273,6 +428,8 @@ if (r && !dev->pm_runtime_disabled) pm_runtime_disable(&pdev->dev); + dw_i2c_acpi_install_space_handler(pdev); + return r; } @@ -336,9 +493,7 @@ struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); i2c_dw_plat_prepare_clk(i_dev, true); - - if (!i_dev->pm_runtime_disabled) - i2c_dw_init(i_dev); + i2c_dw_init(i_dev); return 0; } @@ -383,7 +538,7 @@ { return platform_driver_register(&dw_i2c_driver); } -subsys_initcall(dw_i2c_init_driver); +fs_initcall_sync(dw_i2c_init_driver); static void __exit dw_i2c_exit_driver(void) {