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 <peda@xxxxxxxxxx>: > 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 <chen.kenyy@xxxxxxxxxxxx> >> >> 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 <linux/slab.h> >>> >>> /* >>> - * 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 >> >