Received: by 2002:a25:d7c1:0:0:0:0:0 with SMTP id o184csp4009051ybg; Fri, 25 Oct 2019 12:02:38 -0700 (PDT) X-Google-Smtp-Source: APXvYqy573dfgJMIZgVF8cHeXUu5Kt/ruRBhwftdV/Mx6l4rBWD5BllwmKskkRnQbDLEr/d/SUid X-Received: by 2002:a17:906:3b4e:: with SMTP id h14mr4925450ejf.111.1572030158246; Fri, 25 Oct 2019 12:02:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1572030158; cv=none; d=google.com; s=arc-20160816; b=NBTHDn9prjM/Gh7ey/+TqY+Gyhd05S5DxB8GAQI6e/arOAOugoPT+JkY/tc39ZtVtQ wrx4LhpsWBp/b0A96i9Wgz5EOjDo6DH38ElI9noxfsOHjv7eBlh+/GrUwelJihLyKBf1 U2X7hX0CcsXpLMxMIuV/2RmSCiSfTaat50X/h4JR0nM5Hv9+d3JAstwD6r1fi18aR4Vg UMdC+OaSrXwg6ih+fSvemNDDj0UJVKBG8w9Lzgcf1gKn/Rge3wKtUlhfh719njKY5soB wIHG+rzyGJIiCIAK9u7Mb8MnYqehuNuvXoEBYpaU9TYqaOlyoo5b2YekFTh7mxGq0QAl FReg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=ZwjzHs/HpXYh8lnEtp7uBhL9MhbGxINrdbiilJt1HBc=; b=DvU90SA1ELb8ck8PUVsyuPzFoJhAmx5mYUQULifv5JdFkVR1+9wjjvsd092bZZ2m9/ QK3tECy7zSAPNkvH2J9S8jwjyFXcSQ6cuYeis8o8qTJfkAO1kNtG7BS/S2lQcotTIlwZ 0zHp1IuJ8TCdEWPpXVfNMvrIARtQT3GE7h97vSoVRjtWkcGMjUnTXQlxv2BQjl3EWBXm MlCMSZrW2l2H1TWd0jlYZxncGJCqxslTjIiYXBSYWxjFLIPLpFkZLRnkmlqMrI3EvO1C sgeCpB+PQeBt7cjtN7BVOWV45c06I4MgGaEtQNaQ3jNIcVcAVUrntSAzkx336H02pLMt vCXQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g25si1768109edr.71.2019.10.25.12.02.08; Fri, 25 Oct 2019 12:02:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726846AbfJXUNd (ORCPT + 99 others); Thu, 24 Oct 2019 16:13:33 -0400 Received: from relay10.mail.gandi.net ([217.70.178.230]:43405 "EHLO relay10.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725811AbfJXUNc (ORCPT ); Thu, 24 Oct 2019 16:13:32 -0400 Received: from localhost (unknown [78.193.40.249]) (Authenticated sender: kamel.bouhara@bootlin.com) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 7EF92240004; Thu, 24 Oct 2019 20:13:26 +0000 (UTC) From: Kamel Bouhara To: Wolfram Sang , linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Nicolas Ferre , Alexandre Belloni , Ludovic Desroches , linux-arm-kernel@lists.infradead.org, Thomas Petazzoni , Rob Herring , devicetree@vger.kernel.org, Codrin Ciubotariu Subject: [PATCH v2 1/5] i2c: at91: Send bus clear command if SCL or SDA is down Date: Thu, 24 Oct 2019 22:12:58 +0200 Message-Id: <20191024201302.23376-2-kamel.bouhara@bootlin.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191024201302.23376-1-kamel.bouhara@bootlin.com> References: <20191024201302.23376-1-kamel.bouhara@bootlin.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Codrin Ciubotariu After a transfer timeout, some faulty I2C slave devices might hold down the SCL or the SDA pins. We can generate a bus clear command, hoping that the slave might release the pins. Signed-off-by: Codrin Ciubotariu Acked-by: Ludovic Desroches --- drivers/i2c/busses/i2c-at91-core.c | 8 ++++++++ drivers/i2c/busses/i2c-at91-master.c | 22 ++++++++++++++++++++++ drivers/i2c/busses/i2c-at91.h | 7 ++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index 435c7d7377a3..cb07489e698f 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -68,6 +68,7 @@ static struct at91_twi_pdata at91rm9200_config = { .has_unre_flag = true, .has_alt_cmd = false, .has_hold_field = false, + .has_clear_cmd = false, }; static struct at91_twi_pdata at91sam9261_config = { @@ -76,6 +77,7 @@ static struct at91_twi_pdata at91sam9261_config = { .has_unre_flag = false, .has_alt_cmd = false, .has_hold_field = false, + .has_clear_cmd = false, }; static struct at91_twi_pdata at91sam9260_config = { @@ -84,6 +86,7 @@ static struct at91_twi_pdata at91sam9260_config = { .has_unre_flag = false, .has_alt_cmd = false, .has_hold_field = false, + .has_clear_cmd = false, }; static struct at91_twi_pdata at91sam9g20_config = { @@ -92,6 +95,7 @@ static struct at91_twi_pdata at91sam9g20_config = { .has_unre_flag = false, .has_alt_cmd = false, .has_hold_field = false, + .has_clear_cmd = false, }; static struct at91_twi_pdata at91sam9g10_config = { @@ -100,6 +104,7 @@ static struct at91_twi_pdata at91sam9g10_config = { .has_unre_flag = false, .has_alt_cmd = false, .has_hold_field = false, + .has_clear_cmd = false, }; static const struct platform_device_id at91_twi_devtypes[] = { @@ -130,6 +135,7 @@ static struct at91_twi_pdata at91sam9x5_config = { .has_unre_flag = false, .has_alt_cmd = false, .has_hold_field = false, + .has_clear_cmd = false, }; static struct at91_twi_pdata sama5d4_config = { @@ -138,6 +144,7 @@ static struct at91_twi_pdata sama5d4_config = { .has_unre_flag = false, .has_alt_cmd = false, .has_hold_field = true, + .has_clear_cmd = false, }; static struct at91_twi_pdata sama5d2_config = { @@ -146,6 +153,7 @@ static struct at91_twi_pdata sama5d2_config = { .has_unre_flag = true, .has_alt_cmd = true, .has_hold_field = true, + .has_clear_cmd = true, }; static const struct of_device_id atmel_twi_dt_ids[] = { diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index a3fcc35ffd3b..12d4fa946a82 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -440,6 +440,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; bool has_alt_cmd = dev->pdata->has_alt_cmd; + bool has_clear_cmd = dev->pdata->has_clear_cmd; /* * WARNING: the TXCOMP bit in the Status Register is NOT a clear on @@ -599,6 +600,27 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_THRCLR | AT91_TWI_LOCKCLR); } + + /* + * After timeout, some faulty I2C slave devices might hold SCL/SDA down; + * we can send a bus clear command, hoping that the pins will be + * released + */ + if (has_clear_cmd && + (!(dev->transfer_status & AT91_TWI_SDA) || + !(dev->transfer_status & AT91_TWI_SCL))) { + dev_dbg(dev->dev, + "SDA/SCL are down; sending bus clear command\n"); + if (dev->use_alt_cmd) { + unsigned int acr; + + acr = at91_twi_read(dev, AT91_TWI_ACR); + acr &= ~AT91_TWI_ACR_DATAL_MASK; + at91_twi_write(dev, AT91_TWI_ACR, acr); + } + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_CLEAR); + } + return ret; } diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h index 499b506f6128..0827c28a84db 100644 --- a/drivers/i2c/busses/i2c-at91.h +++ b/drivers/i2c/busses/i2c-at91.h @@ -36,6 +36,7 @@ #define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */ #define AT91_TWI_QUICK BIT(6) /* SMBus quick command */ #define AT91_TWI_SWRST BIT(7) /* Software Reset */ +#define AT91_TWI_CLEAR BIT(15) /* Bus clear command */ #define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */ #define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */ #define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */ @@ -69,6 +70,8 @@ #define AT91_TWI_NACK BIT(8) /* Not Acknowledged */ #define AT91_TWI_EOSACC BIT(11) /* End Of Slave Access */ #define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */ +#define AT91_TWI_SCL BIT(24) /* TWI SCL status */ +#define AT91_TWI_SDA BIT(25) /* TWI SDA status */ #define AT91_TWI_INT_MASK \ (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \ @@ -81,7 +84,8 @@ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ #define AT91_TWI_ACR 0x0040 /* Alternative Command Register */ -#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff) +#define AT91_TWI_ACR_DATAL_MASK GENMASK(15, 0) +#define AT91_TWI_ACR_DATAL(len) ((len) & AT91_TWI_ACR_DATAL_MASK) #define AT91_TWI_ACR_DIR BIT(8) #define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */ @@ -108,6 +112,7 @@ struct at91_twi_pdata { bool has_unre_flag; bool has_alt_cmd; bool has_hold_field; + bool has_clear_cmd; struct at_dma_slave dma_slave; }; -- 2.23.0