--- zzzz-none-000/linux-5.15.111/drivers/i2c/busses/i2c-designware-platdrv.c 2023-05-11 14:00:40.000000000 +0000 +++ puma7-atom-6670-761/linux-5.15.111/drivers/i2c/busses/i2c-designware-platdrv.c 2024-02-07 10:23:01.000000000 +0000 @@ -8,9 +8,15 @@ * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. */ +/* + * Includes Intel Corporation's changes/modifications dated: 2018. + * Changed/modified portions - Copyright (c) 2018, Intel Corporation. + */ #include #include #include +#include +#include #include #include #include @@ -32,6 +38,7 @@ #include #include #include +#include #include "i2c-designware-core.h" @@ -48,6 +55,7 @@ { "INT3433", 0 }, { "80860F41", ACCESS_NO_IRQ_SUSPEND }, { "808622C1", ACCESS_NO_IRQ_SUSPEND }, + { "80862BC1", 0 }, { "AMD0010", ACCESS_INTR_MASK }, { "AMDI0010", ACCESS_INTR_MASK }, { "AMDI0510", 0 }, @@ -61,6 +69,120 @@ MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); #endif +struct dw_i2c_acpi_handler_data { + struct acpi_connection_info info; + struct platform_device *pdev; +}; + +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; +} + #ifdef CONFIG_OF #define BT1_I2C_CTL 0x100 #define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0) @@ -69,6 +191,8 @@ #define BT1_I2C_DI 0x104 #define BT1_I2C_DO 0x108 + + static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val) { struct dw_i2c_dev *dev = context; @@ -262,7 +386,7 @@ goto exit_reset; } - dev->clk = devm_clk_get_optional(&pdev->dev, NULL); + dev->clk = devm_clk_get_optional(&pdev->dev, "baudclk"); if (IS_ERR(dev->clk)) { ret = PTR_ERR(dev->clk); goto exit_reset; @@ -324,6 +448,9 @@ dw_i2c_plat_pm_cleanup(dev); exit_reset: reset_control_assert(dev->rst); + + dw_i2c_acpi_install_space_handler(pdev); + return ret; } @@ -433,7 +560,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) {