diff options
author | Priyanka Jain <Priyanka.Jain@freescale.com> | 2017-05-25 06:45:50 (GMT) |
---|---|---|
committer | Xie Xiaobo <xiaobo.xie@nxp.com> | 2017-07-14 10:09:38 (GMT) |
commit | d0847b698d2313688eba63a5dba35b20ca79ecbd (patch) | |
tree | dcd4f682fe32d48a555914e2b6b178ee7a5e2e72 /drivers/i2c | |
parent | a2d8a0691bc8b300a4d8de5d7d6065e6dad03d02 (diff) | |
download | linux-d0847b698d2313688eba63a5dba35b20ca79ecbd.tar.xz |
i2c: pca954x: Add option to skip disabling PCA954x Mux device
On some Layerscape boards like LS2085ARDB/LS2080ARDB,
input pull-up resistors on PCA954x Mux device are
missing on board. So, if mux are disabled after powered-on,
input lines will float leading to incorrect functionality.
Hence, PCA954x Mux device should never be turned-off after
power-on.
Add option to skip disabling PCA954x Mux device
if device tree contians "i2c-mux-never-disable" property
for pca954x device node.
Signed-off-by: Zhang Ying-22455 <ying.zhang22455@nxp.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/muxes/i2c-mux-pca954x.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 9c4ac26..3c27ab8 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -74,6 +74,7 @@ struct pca954x { u8 last_chan; /* last register value */ u8 deselect; struct i2c_client *client; + u8 disable_mux; /* do not disable mux if val not 0 */ }; /* Provide specs for the PCA954x types we know about */ @@ -196,6 +197,13 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) if (!(data->deselect & (1 << chan))) return 0; +#ifdef CONFIG_ARCH_LAYERSCAPE + if (data->disable_mux != 0) + data->last_chan = data->chip->nchans; + else + data->last_chan = 0; + return pca954x_reg_write(muxc->parent, client, data->disable_mux); +#endif /* Deselect active channel */ data->last_chan = 0; return pca954x_reg_write(muxc->parent, client, data->last_chan); @@ -228,6 +236,28 @@ static int pca954x_probe(struct i2c_client *client, return -ENOMEM; data = i2c_mux_priv(muxc); +#ifdef CONFIG_ARCH_LAYERSCAPE + /* The point here is that you must not disable a mux if there + * are no pullups on the input or you mess up the I2C. This + * needs to be put into the DTS really as the kernel cannot + * know this otherwise. + */ + match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); + if (match) + data->chip = of_device_get_match_data(&client->dev); + else + data->chip = &chips[id->driver_data]; + + data->disable_mux = of_node && + of_property_read_bool(of_node, "i2c-mux-never-disable") && + data->chip->muxtype == pca954x_ismux ? + data->chip->enable : 0; + /* force the first selection */ + if (data->disable_mux != 0) + data->last_chan = data->chip->nchans; + else + data->last_chan = 0; +#endif i2c_set_clientdata(client, muxc); data->client = client; @@ -240,11 +270,16 @@ static int pca954x_probe(struct i2c_client *client, * that the mux is in fact present. This also * initializes the mux to disconnected state. */ +#ifdef CONFIG_ARCH_LAYERSCAPE + if (i2c_smbus_write_byte(client, data->disable_mux) < 0) { +#else if (i2c_smbus_write_byte(client, 0) < 0) { +#endif dev_warn(&client->dev, "probe failed\n"); return -ENODEV; } +#ifndef CONFIG_ARCH_LAYERSCAPE match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) data->chip = of_device_get_match_data(&client->dev); @@ -252,6 +287,7 @@ static int pca954x_probe(struct i2c_client *client, data->chip = &chips[id->driver_data]; data->last_chan = 0; /* force the first selection */ +#endif idle_disconnect_dt = of_node && of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); @@ -312,6 +348,13 @@ static int pca954x_resume(struct device *dev) struct i2c_mux_core *muxc = i2c_get_clientdata(client); struct pca954x *data = i2c_mux_priv(muxc); +#ifdef CONFIG_ARCH_LAYERSCAPE + if (data->disable_mux != 0) + data->last_chan = data->chip->nchans; + else + data->last_chan = 0; + return i2c_smbus_write_byte(client, data->disable_mux); +#endif data->last_chan = 0; return i2c_smbus_write_byte(client, 0); } |