From patchwork Mon Aug 11 21:28:54 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 379142 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 98323140140 for ; Tue, 12 Aug 2014 07:22:44 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752329AbaHKVWn (ORCPT ); Mon, 11 Aug 2014 17:22:43 -0400 Received: from mga09.intel.com ([134.134.136.24]:31522 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752097AbaHKVWm (ORCPT ); Mon, 11 Aug 2014 17:22:42 -0400 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 11 Aug 2014 14:16:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.01,844,1400050800"; d="scan'208";a="557064938" Received: from spandruv-desktop.jf.intel.com ([10.7.199.159]) by orsmga001.jf.intel.com with ESMTP; 11 Aug 2014 14:22:41 -0700 From: Srinivas Pandruvada To: wsa@the-dreams.de, rafael.j.wysocki@intel.com Cc: linux-i2c@vger.kernel.org, mika.westerberg@linux.intel.com, srinivas.pandruvada@linux.intel.com Subject: [PATCH v1 1/2] i2c / ACPI: Create device on a valid first address Date: Mon, 11 Aug 2014 14:28:54 -0700 Message-Id: <1407792535-21681-2-git-send-email-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1407792535-21681-1-git-send-email-srinivas.pandruvada@linux.intel.com> References: <1407792535-21681-1-git-send-email-srinivas.pandruvada@linux.intel.com> Sender: linux-i2c-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org The ACPI spec allows multiple I2cSerialBus addresses for a single device. The current logic creates a i2c device for the last I2cSerialBus address. In many configuration the first address is valid not the last one. But in some configuration it is possible that the chosen address is not valid, so skip to next address and create a device on it. Examples: 1. Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (RBUF, ResourceTemplate () { I2cSerialBus (0x0068, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2C5", 0x00, ResourceConsumer, , ) I2cSerialBus (0x000C, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2C5", 0x00, ResourceConsumer, , ) Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, ) { 0x00000044, } }) Return (RBUF) } This device is a combo device, where the first address is a valid address of the main controller device. So this change will create i2c device for 0x068, the first address. 2. Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings { Name (SBUF, ResourceTemplate () { I2cSerialBus (0x000C, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2C3", 0x00, ResourceConsumer, , ) I2cSerialBus (0x0048, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.I2C3", 0x00, ResourceConsumer, , ) Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, ) { 0x00000033, } }) Return (SBUF) } This device is a SMBUS compliant, where 0x0C is address of alert response address (ARA). This patch will skip 0x0C, as this is reserved address, and will create an i2c device at 0x48. Signed-off-by: Srinivas Pandruvada Signed-off-by: Mika Westerberg --- drivers/i2c/i2c-core.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 66aa83b..31b9341 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -543,6 +543,28 @@ static int i2c_check_addr_validity(unsigned short addr) return 0; } +static int i2c_smbus_match_reserved_addr(unsigned short addr) +{ + /* + * Reserved addresses per SMBUS specification + * in addition to i2c reserved addresses: + * 0x08 SMBUS Host + * 0x0C ARA + * 0x61 Device default address + * 0x28 Access bus host + * 0x37 Access bus default addr + */ + int i; + u8 resvd_addrs[] = {0x08, 0x0C, 0x061, 0x28, 0x37}; + + for (i = 0; i < ARRAY_SIZE(resvd_addrs); ++i) { + if (resvd_addrs[i] == addr) + return 0; + } + + return -EINVAL; +} + static int __i2c_check_addr_busy(struct device *dev, void *addrp) { struct i2c_client *client = i2c_verify_client(dev); @@ -1109,6 +1131,22 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) sb = &ares->data.i2c_serial_bus; if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + if (info->addr) { + /* + * We have multiple I2cSerialBus present. Check + * the validity of last parsed address. + * i2c device create rejects reserved address + * for i2C. But if the last address was an + * invalid i2c address or SMBUS reserved + * address, skip to next valid address in the + * list and call i2c_new_device for this + * address instead. + */ + if (!i2c_check_addr_validity(info->addr) && + i2c_smbus_match_reserved_addr( + info->addr)) + return 1; /* last addr was valid */ + } info->addr = sb->slave_address; if (sb->access_mode == ACPI_I2C_10BIT_MODE) info->flags |= I2C_CLIENT_TEN;