Received: by 10.192.165.156 with SMTP id m28csp360195imm; Fri, 13 Apr 2018 00:01:16 -0700 (PDT) X-Google-Smtp-Source: AIpwx4/MUcmE7ub1ZKreFIbMYSpS0GcBJy7MpJeMXyE2KpuLo+HOEVC9yFwNXVUvfdvHWO/YQngB X-Received: by 2002:a17:902:4001:: with SMTP id b1-v6mr4018093pld.273.1523602876013; Fri, 13 Apr 2018 00:01:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523602875; cv=none; d=google.com; s=arc-20160816; b=c/QTSDhQroFLmcqY4agPR9Is5Ugj7Li8AXn+tYhZFta48DL/n9P3YDudY57QMXDsgX 9xbtCWQmNym5U2copWfvVtBas2WH4uvSfHfSPBY4NOigfWyQaVAlKsg96XeWFHbV8hne 3KVkudixJk1jSOIS1gBraV9lC/6/A/LDwGTZWqFMABTVfx7zdjw+1VnE+lk5cslWNK8g LWArDed2gTvnnjTC2bK/pLMhPVWTjwr+vrew+qz/lL3dPDDB9yod3+ZHSU7rMXWIiS69 mMQohklIDurJSsYHFuBlEaVFV8UtPI5FClDFLVk/sp/wt/w0kUKihpYAzNWFhfRYHiVt OTtw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:arc-authentication-results; bh=qoKjEeG7WoodRYolb8m54qJTv0tjocqO8Rj43y7W2YE=; b=Kx8zjNkZj25n2Zo25ZTt0fd440XLnihQDvgNF9GiQxH0au9o8S5LRtORMcm4qzWFyS ItAxTKlyERanlgMX0GklAgAgpp1Y7+eorzSHzzYBfYlCQ9we/5i2V1ENltL4eRTja4k4 NJKHm7N719QThGZAF/vkbR8L9c0MRU2UsrIsLgKAsnElT93HyhQy2Aiya4pR1iC0kgqB poSFEoDee1negVc9poZnt6EiF1OlqdJeVpkBaXPYg3tTDg0rfvIR0XJFkwdr71f3Z+xm zxn1CxUYJWCZOAKvzApZFtqg5nUmiJWvTelarSjyY0uTlce4kkvaLhd1wxvpZsWqTber 6kmA== 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 q4-v6si529781pll.261.2018.04.13.00.01.01; Fri, 13 Apr 2018 00:01:15 -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 S1753454AbeDMG7j (ORCPT + 99 others); Fri, 13 Apr 2018 02:59:39 -0400 Received: from hub02.inventec.com ([218.32.67.167]:6997 "EHLO mail.inventec.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750849AbeDMG7i (ORCPT ); Fri, 13 Apr 2018 02:59:38 -0400 Received: from IEC1-MSE-FE1.inventec.com (10.1.254.203) by IEC1-EX2010-04.iec.inventec (10.1.254.157) with Microsoft SMTP Server id 14.3.361.1; Fri, 13 Apr 2018 14:59:36 +0800 Received: from IEC1-SPAM-2.inventec.com (smg2.inventec.com [10.1.254.202]) by IEC1-MSE-FE1.inventec.com with ESMTP id w3D6xGS0056257 for ; Fri, 13 Apr 2018 14:59:16 +0800 (GMT-8) (envelope-from chen.kenyy@inventec.com) Received: from mail-lf0-f72.google.com (mail-lf0-f72.google.com [209.85.215.72]) by IEC1-SPAM-2.inventec.com with ESMTP id w3D6xCF0023556 (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 13 Apr 2018 14:59:14 +0800 (GMT-8) (envelope-from chen.kenyy@inventec.com) Received: by mail-lf0-f72.google.com with SMTP id 95-v6so2320923lfv.12 for ; Thu, 12 Apr 2018 23:59:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=qoKjEeG7WoodRYolb8m54qJTv0tjocqO8Rj43y7W2YE=; b=qEztqIUMMpmjnUnS+2S0ZdkCTTMv893x2vOXjWdkRkgYhsO7TVi8Jn9fEgnT23KK5w rpKvG2kh07x8PBVA+Lw8XD5zYq5QGS9ro5IAk56fYPMDrHX/Z6dxcLH4iDNx6pH5ed2p 6hlA/PaiIIW5WNkdMdOsaFQ6/AF0AptJbrUVLEsJz0U0Eb5y4RGKOQ/yIooATgn+Apfk XXqFwgtd31L2mUmc0VFfC1msZiIcQfRPhwT3YoANlrh5BD6YvhDRNHEkETA9O5n7Cobx CCN0jnw9qc3/q2OMKEUjJS5FLEzXT9T5FEBi/RxhGQSdjEmqrnk1TAYsrg63jG4BNElN N2jQ== X-Gm-Message-State: ALQs6tAgkbCnaUsv7dbskuUOSm0JmiVOLq89CuAmiVzepSM4B+/H+bN9 E0jUQX+NpnvOpsh/EnHt9LThx67yV1urpHg9tMxgvJUKSgMuXx/3telqv6RZcGt63toJYgxppRc JJJcie1wuJwwRimPiNnpDqSQ4pGeMOr5gH/fv+AKmaro= X-Received: by 2002:a19:f24c:: with SMTP id d12-v6mr7808048lfk.111.1523602750751; Thu, 12 Apr 2018 23:59:10 -0700 (PDT) X-Received: by 2002:a19:f24c:: with SMTP id d12-v6mr7808026lfk.111.1523602750297; Thu, 12 Apr 2018 23:59:10 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a19:d10d:0:0:0:0:0 with HTTP; Thu, 12 Apr 2018 23:59:09 -0700 (PDT) In-Reply-To: <5053d0d0-e4c5-733e-051d-b5900d05ea2b@axentia.se> References: <20180320061909.5775-1-chen.kenyy@inventec.com> <20180320093200.19179-1-peda@axentia.se> <5053d0d0-e4c5-733e-051d-b5900d05ea2b@axentia.se> From: =?UTF-8?B?Q2hlbktlbllZIOmZs+awuOeHnyBUQU8=?= Date: Fri, 13 Apr 2018 14:59:09 +0800 Message-ID: Subject: Re: [PATCH linux dev-4.16 v2] i2c: muxes: pca9641: new driver To: Peter Rosin CC: , Guenter Roeck , Wolfram Sang , Joel Stanley , Content-Type: text/plain; charset="UTF-8" X-DNSRBL: X-MAIL: IEC1-MSE-FE1.inventec.com w3D6xGS0056257 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Peter, Sorry for late. Here has some event at my company which needs to pause this work. If the status changed, I will update my patch. Thanks. Ken 2018-04-11 17:37 GMT+08:00 Peter Rosin : > Hi Ken, > > It's been a couple of weeks and I wondered if you are making any > progress? Simple lack of time perhaps, or are you stuck and need > help? > > Cheers, > Peter > > On 2018-03-20 10:31, Peter Rosin wrote: >> On 2018-03-20 07:19, Ken Chen wrote: >>> Signed-off-by: Ken Chen >> >> Ok, now that you are not adding a new driver, but instead >> modify an existing driver, the subject I requested in no >> longer relevant. Now I would like to see: >> >> i2c: mux: pca9541: add support for PCA9641 chips >> >> Or something like that. >> >>> --- >>> v1->v2 >>> - Merged PCA9641 code into i2c-mux-pca9541.c >>> - Modified title >>> - Add PCA9641 detect function >>> --- >>> drivers/i2c/muxes/i2c-mux-pca9541.c | 184 ++++++++++++++++++++++++++++++++++-- >>> 1 file changed, 174 insertions(+), 10 deletions(-) >>> >>> diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c >>> index 6a39ada..493f947 100644 >>> --- a/drivers/i2c/muxes/i2c-mux-pca9541.c >>> +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c >>> @@ -1,5 +1,5 @@ >>> /* >>> - * I2C multiplexer driver for PCA9541 bus master selector >>> + * I2C multiplexer driver for PCA9541/PCA9641 bus master selector >>> * >>> * Copyright (c) 2010 Ericsson AB. >>> * >>> @@ -26,8 +26,8 @@ >>> #include >>> >>> /* >>> - * The PCA9541 is a bus master selector. It supports two I2C masters connected >>> - * to a single slave bus. >>> + * The PCA9541/PCA9641 is a bus master selector. It supports two I2C masters >> >> PCA9541 and PCA9641 are bus master selectors. They support two I2C masters >> >> And make sure to lose the trailing space. >> >>> + * connected to a single slave bus. >>> * >>> * Before each bus transaction, a master has to acquire bus ownership. After the >>> * transaction is complete, bus ownership has to be released. This fits well >>> @@ -58,11 +58,43 @@ >>> #define PCA9541_ISTAT_MYTEST (1 << 6) >>> #define PCA9541_ISTAT_NMYTEST (1 << 7) >>> >>> +#define PCA9641_ID 0x00 >>> +#define PCA9641_ID_MAGIC 0x38 >>> + >>> +#define PCA9641_CONTROL 0x01 >>> +#define PCA9641_STATUS 0x02 >>> +#define PCA9641_TIME 0x03 >>> + >>> +#define PCA9641_CTL_LOCK_REQ BIT(0) >>> +#define PCA9641_CTL_LOCK_GRANT BIT(1) >>> +#define PCA9641_CTL_BUS_CONNECT BIT(2) >>> +#define PCA9641_CTL_BUS_INIT BIT(3) >>> +#define PCA9641_CTL_SMBUS_SWRST BIT(4) >>> +#define PCA9641_CTL_IDLE_TIMER_DIS BIT(5) >>> +#define PCA9641_CTL_SMBUS_DIS BIT(6) >>> +#define PCA9641_CTL_PRIORITY BIT(7) >>> + >>> +#define PCA9641_STS_OTHER_LOCK BIT(0) >>> +#define PCA9641_STS_BUS_INIT_FAIL BIT(1) >>> +#define PCA9641_STS_BUS_HUNG BIT(2) >>> +#define PCA9641_STS_MBOX_EMPTY BIT(3) >>> +#define PCA9641_STS_MBOX_FULL BIT(4) >>> +#define PCA9641_STS_TEST_INT BIT(5) >>> +#define PCA9641_STS_SCL_IO BIT(6) >>> +#define PCA9641_STS_SDA_IO BIT(7) >>> + >>> +#define PCA9641_RES_TIME 0x03 >>> + >>> #define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON) >>> #define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS) >>> #define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) >>> #define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) >>> >>> +#define BUSOFF(x, y) (!((x) & PCA9641_CTL_LOCK_GRANT) && \ >>> + !((y) & PCA9641_STS_OTHER_LOCK)) >>> +#define other_lock(x) ((x) & PCA9641_STS_OTHER_LOCK) >>> +#define lock_grant(x) ((x) & PCA9641_CTL_LOCK_GRANT) >> These macro names are now completely hideous. They were bad before, >> but this is just too much for me. So, instead of adding BUSOFF etc, >> I would like to see all the macros with a chip prefix. But I think >> they will get overly long, so I think you should just write trivial >> pca9541_mybus, pca9541_busoff, pca9641_busoff etc functions. The >> compiler should inline them just fine. >> >> The rename of the existing macros and their conversion to functions >> should be in the first preparatory patch that I mention below. The >> new functions should be in the second patch. >> >>> + >>> /* arbitration timeouts, in jiffies */ >>> #define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ >>> #define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ >>> @@ -79,6 +111,7 @@ struct pca9541 { >>> >>> static const struct i2c_device_id pca9541_id[] = { >>> {"pca9541", 0}, >>> + {"pca9641", 1}, >> >> You are actually not using this 0/1 difference. Have a look at >> e.g. how the i2c-mux-pca954x driver uses this as an index into >> a chip description array. I would like to see something similar >> here... >> >>> {} >>> }; >>> >>> @@ -87,6 +120,7 @@ MODULE_DEVICE_TABLE(i2c, pca9541_id); >>> #ifdef CONFIG_OF >>> static const struct of_device_id pca9541_of_match[] = { >>> { .compatible = "nxp,pca9541" }, >>> + { .compatible = "nxp,pca9641" }, >> >> ...including pointers to the above chip descriptions here, just >> like the pca954x driver. >> >>> {} >>> }; >>> MODULE_DEVICE_TABLE(of, pca9541_of_match); >>> @@ -328,6 +362,125 @@ static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) >>> } >>> >>> /* >>> + * Arbitration management functions >>> + */ >>> +static void pca9641_release_bus(struct i2c_client *client) >>> +{ >>> + pca9541_reg_write(client, PCA9641_CONTROL, 0); >>> +} >>> + >>> +/* >>> + * Channel arbitration >>> + * >>> + * Return values: >>> + * <0: error >>> + * 0 : bus not acquired >>> + * 1 : bus acquired >>> + */ >>> +static int pca9641_arbitrate(struct i2c_client *client) >>> +{ >>> + struct i2c_mux_core *muxc = i2c_get_clientdata(client); >>> + struct pca9541 *data = i2c_mux_priv(muxc); >>> + int reg_ctl, reg_sts; >>> + >>> + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); >>> + if (reg_ctl < 0) >>> + return reg_ctl; >>> + reg_sts = pca9541_reg_read(client, PCA9641_STATUS); >>> + >>> + if (BUSOFF(reg_ctl, reg_sts)) { >>> + /* >>> + * Bus is off. Request ownership or turn it on unless >>> + * other master requested ownership. >>> + */ >>> + reg_ctl |= PCA9641_CTL_LOCK_REQ; >>> + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); >>> + reg_ctl = pca9541_reg_read(client, PCA9641_CONTROL); >>> + >>> + if (lock_grant(reg_ctl)) { >>> + /* >>> + * Other master did not request ownership, >>> + * or arbitration timeout expired. Take the bus. >>> + */ >>> + reg_ctl |= PCA9641_CTL_BUS_CONNECT >>> + | PCA9641_CTL_LOCK_REQ; >>> + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); >>> + data->select_timeout = SELECT_DELAY_SHORT; >>> + >>> + return 1; >>> + } else { >>> + /* >>> + * Other master requested ownership. >>> + * Set extra long timeout to give it time to acquire it. >>> + */ >>> + data->select_timeout = SELECT_DELAY_LONG * 2; >>> + } >>> + } else if (lock_grant(reg_ctl)) { >>> + /* >>> + * Bus is on, and we own it. We are done with acquisition. >>> + */ >>> + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; >>> + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); >>> + >>> + return 1; >>> + } else if (other_lock(reg_sts)) { >>> + /* >>> + * Other master owns the bus. >>> + * If arbitration timeout has expired, force ownership. >>> + * Otherwise request it. >>> + */ >>> + data->select_timeout = SELECT_DELAY_LONG; >>> + reg_ctl |= PCA9641_CTL_LOCK_REQ; >>> + pca9541_reg_write(client, PCA9641_CONTROL, reg_ctl); >>> + } >>> + return 0; >>> +} >>> + >>> +static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) >>> +{ >>> + struct pca9541 *data = i2c_mux_priv(muxc); >>> + struct i2c_client *client = data->client; >>> + int ret; >>> + unsigned long timeout = jiffies + ARB2_TIMEOUT; >>> + /* give up after this time */ >>> + >>> + data->arb_timeout = jiffies + ARB_TIMEOUT; >>> + /* force bus ownership after this time */ >>> + >>> + do { >>> + ret = pca9641_arbitrate(client); >>> + if (ret) >>> + return ret < 0 ? ret : 0; >>> + >>> + if (data->select_timeout == SELECT_DELAY_SHORT) >>> + udelay(data->select_timeout); >>> + else >>> + msleep(data->select_timeout / 1000); >>> + } while (time_is_after_eq_jiffies(timeout)); >>> + >>> + return -ETIMEDOUT; >>> +} >>> + >>> +static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) >>> +{ >>> + struct pca9541 *data = i2c_mux_priv(muxc); >>> + struct i2c_client *client = data->client; >>> + >>> + pca9641_release_bus(client); >>> + return 0; >>> +} >> >> The pca9641_select_chan and pca9641_release_chan functions are exact >> copies of the pca9541 counterparts, with the exception of which >> functions they ultimately call. So, instead of using different >> function pointers in the i2c_mux_alloc calls below, add a couple of >> function pointers to the above mentioned chip description struct. >> >> Then change pca9541_release_chan to something like this: >> >> static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) >> { >> struct pca9541 *data = i2c_mux_priv(muxc); >> struct i2c_client *client = data->client; >> >> data->chip->release_bus(client); >> return 0; >> } >> >> Similarly for the *_select_chan "wrapper". >> >> Now, these changes will somewhat affect the pca9541 side of the >> driver, so I would like to see more than one patch. There should be >> patches that prepares the driver that should be kind of easy to >> verify that they are equivalent but that makes adding a new chip >> easier, and then one patch at then end that adds the new chip. Hmm, >> it will probably be easier if I write those patches instead of >> reviewing them. I will followup with them. But note that I can >> only compile test them, so I would like to see tags for them. >> >>> + >>> +static int pca9641_detect_id(struct i2c_client *client) >>> +{ >>> + int reg; >>> + >>> + reg = pca9541_reg_read(client, PCA9641_ID); >>> + if (reg == PCA9641_ID_MAGIC) >>> + return 1; >>> + else >>> + return 0; >>> +} >> >> This was not what I had in mind. If you do dig out the id, I think >> you should only use it to verify that the input to the probe function >> is correct and error out otherwise. But maybe I'm conservative? >> Anyway, with the above patches you will not need this. >> >>> +/* >>> * I2C init/probing/exit functions >>> */ >>> static int pca9541_probe(struct i2c_client *client, >>> @@ -339,34 +492,45 @@ static int pca9541_probe(struct i2c_client *client, >>> struct pca9541 *data; >>> int force; >>> int ret; >>> + int detect_id; >>> >>> if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) >>> return -ENODEV; >>> >>> + detect_id = pca9641_detect_id(client); >>> /* >>> * I2C accesses are unprotected here. >>> * We have to lock the adapter before releasing the bus. >>> */ >>> - i2c_lock_adapter(adap); >>> - pca9541_release_bus(client); >>> - i2c_unlock_adapter(adap); >>> - >>> + if (detect_id == 0) { >>> + i2c_lock_adapter(adap); >>> + pca9541_release_bus(client); >>> + i2c_unlock_adapter(adap); >>> + } else { >>> + i2c_lock_adapter(adap); >>> + pca9641_release_bus(client); >>> + i2c_unlock_adapter(adap); >>> + } >>> /* Create mux adapter */ >>> >>> force = 0; >>> if (pdata) >>> force = pdata->modes[0].adap_id; >>> - muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), >>> + if (detect_id == 0) { >>> + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), >>> I2C_MUX_ARBITRATOR, >>> pca9541_select_chan, pca9541_release_chan); >>> + } else { >>> + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), >>> + I2C_MUX_ARBITRATOR, >>> + pca9641_select_chan, pca9641_release_chan); >>> + } >>> if (!muxc) >>> return -ENOMEM; >>> >>> data = i2c_mux_priv(muxc); >>> data->client = client; >>> - >>> i2c_set_clientdata(client, muxc); >>> - >> >> Please don't do spurious whitespace changes like this as part of a >> functional change. >> >>> ret = i2c_mux_add_adapter(muxc, force, 0, 0); >>> if (ret) >>> return ret; >>> >> >> You should change the Kconfig file to mention the new chip and you are >> still missing a devicetree binding. >> >> Cheers, >> Peter >> >