From patchwork Wed Nov 16 10:48:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Russell King (Oracle)" X-Patchwork-Id: 9431231 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CFCE56047D for ; Wed, 16 Nov 2016 10:51:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B2C8A28E9C for ; Wed, 16 Nov 2016 10:51:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A461828EFC; Wed, 16 Nov 2016 10:51:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C98E028E9C for ; Wed, 16 Nov 2016 10:51:22 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1c6xmx-0006l0-8g; Wed, 16 Nov 2016 10:49:59 +0000 Received: from pandora.armlinux.org.uk ([2001:4d48:ad52:3201:214:fdff:fe10:1be6]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1c6xmW-0006bL-UX for linux-arm-kernel@lists.infradead.org; Wed, 16 Nov 2016 10:49:34 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=armlinux.org.uk; s=pandora-2014; h=Date:Sender:Message-Id:Content-Type:Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From; bh=KJGseyuYPVdf/pvK4MMF5GIoc62qf/ELSSyH2iP/Ngk=; b=i8OTwfeKy9T6NyY4IIrTkMTQ/konxqPCwYnE1EqzqJiYjGjyHCQPlLgT60MIZo5eBe0krNWJTYim64jmnx58qZ3fYC5DZXgQKa47f/6RNMlHAVSFbbiv+iGMXxsEkXjVRHgVt5ZG/vOltAQ/MQhivYFpPHKfhdHTpuM6SMkL4aw=; Received: from e0022681537dd.dyn.armlinux.org.uk ([2002:4e20:1eda:1:222:68ff:fe15:37dd]:60322 helo=rmk-PC.armlinux.org.uk) by pandora.armlinux.org.uk with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.82_1-5b7a7c0-XX) (envelope-from ) id 1c6xly-0000WZ-Rd; Wed, 16 Nov 2016 10:48:59 +0000 Received: from rmk by rmk-PC.armlinux.org.uk with local (Exim 4.82_1-5b7a7c0-XX) (envelope-from ) id 1c6xlx-0006wl-Py; Wed, 16 Nov 2016 10:48:57 +0000 From: Russell King To: Brian Starkey , Liviu Dudau , Jyri Sarha Subject: [PATCH 2/2] drm/i2c: tda998x: allow sharing of the CEC device accesses MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Wed, 16 Nov 2016 10:48:57 +0000 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161116_024933_642014_0673AB52 X-CRM114-Status: GOOD ( 16.72 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: David Airlie , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP cec_read() is non-atomic in the presence of other I2C bus transactions to the same device. This presents a problem when we add support for the TDA9950 CEC engine part - both drivers can be trying to access the device. Avoid the inherent problems by switching to i2c_transfer() instead, which allows us to perform more than one bus transaction atomically. As this means we will be using I2C transactions rather than SMBUS, we have to check that the host supports I2C functionality. Signed-off-by: Russell King --- drivers/gpu/drm/i2c/tda998x_drv.c | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 74fb59a35269..f59d6664315d 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -41,6 +41,7 @@ struct tda998x_priv { struct i2c_client *hdmi; struct mutex mutex; u16 rev; + u8 cec_addr; u8 current_page; bool is_on; bool supports_infoframes; @@ -374,35 +375,46 @@ struct tda998x_priv { static void cec_write(struct tda998x_priv *priv, u16 addr, u8 val) { - struct i2c_client *client = priv->cec; u8 buf[] = {addr, val}; + struct i2c_msg msg = { + .addr = priv->cec_addr, + .len = 2, + .buf = buf, + }; int ret; - ret = i2c_master_send(client, buf, sizeof(buf)); + ret = i2c_transfer(priv->hdmi->adapter, &msg, 1); if (ret < 0) - dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr); + dev_err(&priv->hdmi->dev, "Error %d writing to cec:0x%x\n", + ret, addr); } static u8 cec_read(struct tda998x_priv *priv, u8 addr) { - struct i2c_client *client = priv->cec; u8 val; + struct i2c_msg msg[2] = { + { + .addr = priv->cec_addr, + .len = 1, + .buf = &addr, + }, { + .addr = priv->cec_addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &val, + }, + }; int ret; - ret = i2c_master_send(client, &addr, sizeof(addr)); - if (ret < 0) - goto fail; - - ret = i2c_master_recv(client, &val, sizeof(val)); - if (ret < 0) - goto fail; + ret = i2c_transfer(priv->hdmi->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + dev_err(&priv->hdmi->dev, "Error %d reading from cec:0x%x\n", + ret, addr); + val = 0; + } return val; - -fail: - dev_err(&client->dev, "Error %d reading from cec:0x%x\n", ret, addr); - return 0; } static int @@ -1471,17 +1483,16 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv) struct device_node *np = client->dev.of_node; u32 video; int rev_lo, rev_hi, ret; - unsigned short cec_addr; priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); + /* CEC I2C address bound to TDA998x I2C addr by configuration pins */ + priv->cec_addr = 0x34 + (client->addr & 0x03); priv->current_page = 0xff; priv->hdmi = client; - /* CEC I2C address bound to TDA998x I2C addr by configuration pins */ - cec_addr = 0x34 + (client->addr & 0x03); - priv->cec = i2c_new_dummy(client->adapter, cec_addr); + priv->cec = i2c_new_dummy(client->adapter, priv->cec_addr); if (!priv->cec) return -ENODEV; @@ -1722,6 +1733,10 @@ static const struct component_ops tda998x_ops = { static int tda998x_probe(struct i2c_client *client, const struct i2c_device_id *id) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_warn(&client->dev, "adapter does not support I2C\n"); + return -EIO; + } return component_add(&client->dev, &tda998x_ops); }