aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.4/8233-i2c-pca954x-Add-option-to-skip-disabling-PCA954x-Mux.patch
blob: 0967aeb6982f6752a42b1297fbe9bf5c6f65b499 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
From a4be9046c3a3fc39a06089553df8cc19a2abd814 Mon Sep 17 00:00:00 2001
From: Priyanka Jain <Priyanka.Jain@freescale.com>
Date: Tue, 3 Nov 2015 11:25:24 +0530
Subject: [PATCH 233/238] 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: Priyanka Jain <Priyanka.Jain@freescale.com>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c |   38 +++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index acfcef3..386f86f 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -63,6 +63,7 @@ struct pca954x {
 	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
 
 	u8 last_chan;		/* last register value */
+	u8 disable_mux;		/* do not disable mux if val not 0 */
 };
 
 struct chip_desc {
@@ -174,6 +175,13 @@ static int pca954x_deselect_mux(struct i2c_adapter *adap,
 {
 	struct pca954x *data = i2c_get_clientdata(client);
 
+#ifdef CONFIG_ARCH_LAYERSCAPE
+	if (data->disable_mux != 0)
+		data->last_chan = chips[data->type].nchans;
+	else
+		data->last_chan = 0;
+	return pca954x_reg_write(adap, client, data->disable_mux);
+#endif
 	/* Deselect active channel */
 	data->last_chan = 0;
 	return pca954x_reg_write(adap, client, data->last_chan);
@@ -201,6 +209,23 @@ static int pca954x_probe(struct i2c_client *client,
 	if (!data)
 		return -ENOMEM;
 
+#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.
+	 */
+	data->type = id->driver_data;
+	data->disable_mux = of_node &&
+		of_property_read_bool(of_node, "i2c-mux-never-disable") &&
+		chips[data->type].muxtype == pca954x_ismux ?
+		chips[data->type].enable : 0;
+	/* force the first selection */
+	if (data->disable_mux != 0)
+		data->last_chan = chips[data->type].nchans;
+	else
+		data->last_chan = 0;
+#endif
 	i2c_set_clientdata(client, data);
 
 	/* Get the mux out of reset if a reset GPIO is specified. */
@@ -212,13 +237,19 @@ 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
 	data->type = 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");
@@ -289,6 +320,13 @@ static int pca954x_resume(struct device *dev)
 	struct i2c_client *client = to_i2c_client(dev);
 	struct pca954x *data = i2c_get_clientdata(client);
 
+#ifdef CONFIG_ARCH_LAYERSCAPE
+	if (data->disable_mux != 0)
+		data->last_chan = chips[data->type].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);
 }
-- 
1.7.9.5