xref: /openbmc/linux/drivers/i2c/busses/i2c-powermac.c (revision 3a3dd0186f619b74e61e6f29dddcaf59af7d3cac)
1a28d3af2SBenjamin Herrenschmidt /*
2a28d3af2SBenjamin Herrenschmidt     i2c Support for Apple SMU Controller
3a28d3af2SBenjamin Herrenschmidt 
4a28d3af2SBenjamin Herrenschmidt     Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
5a28d3af2SBenjamin Herrenschmidt                        <benh@kernel.crashing.org>
6a28d3af2SBenjamin Herrenschmidt 
7a28d3af2SBenjamin Herrenschmidt     This program is free software; you can redistribute it and/or modify
8a28d3af2SBenjamin Herrenschmidt     it under the terms of the GNU General Public License as published by
9a28d3af2SBenjamin Herrenschmidt     the Free Software Foundation; either version 2 of the License, or
10a28d3af2SBenjamin Herrenschmidt     (at your option) any later version.
11a28d3af2SBenjamin Herrenschmidt 
12a28d3af2SBenjamin Herrenschmidt     This program is distributed in the hope that it will be useful,
13a28d3af2SBenjamin Herrenschmidt     but WITHOUT ANY WARRANTY; without even the implied warranty of
14a28d3af2SBenjamin Herrenschmidt     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15a28d3af2SBenjamin Herrenschmidt     GNU General Public License for more details.
16a28d3af2SBenjamin Herrenschmidt 
17a28d3af2SBenjamin Herrenschmidt     You should have received a copy of the GNU General Public License
18a28d3af2SBenjamin Herrenschmidt     along with this program; if not, write to the Free Software
19a28d3af2SBenjamin Herrenschmidt     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20a28d3af2SBenjamin Herrenschmidt 
21a28d3af2SBenjamin Herrenschmidt */
22a28d3af2SBenjamin Herrenschmidt 
23a28d3af2SBenjamin Herrenschmidt #include <linux/module.h>
24a28d3af2SBenjamin Herrenschmidt #include <linux/kernel.h>
25a28d3af2SBenjamin Herrenschmidt #include <linux/types.h>
26a28d3af2SBenjamin Herrenschmidt #include <linux/i2c.h>
27a28d3af2SBenjamin Herrenschmidt #include <linux/init.h>
28a28d3af2SBenjamin Herrenschmidt #include <linux/device.h>
29a28d3af2SBenjamin Herrenschmidt #include <linux/platform_device.h>
30a28d3af2SBenjamin Herrenschmidt #include <asm/prom.h>
31a28d3af2SBenjamin Herrenschmidt #include <asm/pmac_low_i2c.h>
32a28d3af2SBenjamin Herrenschmidt 
33a28d3af2SBenjamin Herrenschmidt MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
34a28d3af2SBenjamin Herrenschmidt MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
35a28d3af2SBenjamin Herrenschmidt MODULE_LICENSE("GPL");
36a28d3af2SBenjamin Herrenschmidt 
37a28d3af2SBenjamin Herrenschmidt /*
38a28d3af2SBenjamin Herrenschmidt  * SMBUS-type transfer entrypoint
39a28d3af2SBenjamin Herrenschmidt  */
40a28d3af2SBenjamin Herrenschmidt static s32 i2c_powermac_smbus_xfer(	struct i2c_adapter*	adap,
41a28d3af2SBenjamin Herrenschmidt 					u16			addr,
42a28d3af2SBenjamin Herrenschmidt 					unsigned short		flags,
43a28d3af2SBenjamin Herrenschmidt 					char			read_write,
44a28d3af2SBenjamin Herrenschmidt 					u8			command,
45a28d3af2SBenjamin Herrenschmidt 					int			size,
46a28d3af2SBenjamin Herrenschmidt 					union i2c_smbus_data*	data)
47a28d3af2SBenjamin Herrenschmidt {
48a28d3af2SBenjamin Herrenschmidt 	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
49a28d3af2SBenjamin Herrenschmidt 	int			rc = 0;
50a28d3af2SBenjamin Herrenschmidt 	int			read = (read_write == I2C_SMBUS_READ);
51a28d3af2SBenjamin Herrenschmidt 	int			addrdir = (addr << 1) | read;
5202864d58SJean Delvare 	int			mode, subsize, len;
5302864d58SJean Delvare 	u32			subaddr;
5402864d58SJean Delvare 	u8			*buf;
55a28d3af2SBenjamin Herrenschmidt 	u8			local[2];
56a28d3af2SBenjamin Herrenschmidt 
5702864d58SJean Delvare 	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
5802864d58SJean Delvare 		mode = pmac_i2c_mode_std;
5902864d58SJean Delvare 		subsize = 0;
6002864d58SJean Delvare 		subaddr = 0;
6102864d58SJean Delvare 	} else {
6202864d58SJean Delvare 		mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
6302864d58SJean Delvare 		subsize = 1;
6402864d58SJean Delvare 		subaddr = command;
6502864d58SJean Delvare 	}
66a28d3af2SBenjamin Herrenschmidt 
67a28d3af2SBenjamin Herrenschmidt 	switch (size) {
68a28d3af2SBenjamin Herrenschmidt         case I2C_SMBUS_QUICK:
6902864d58SJean Delvare 		buf = NULL;
7002864d58SJean Delvare 		len = 0;
71a28d3af2SBenjamin Herrenschmidt 	    	break;
72a28d3af2SBenjamin Herrenschmidt         case I2C_SMBUS_BYTE:
73a28d3af2SBenjamin Herrenschmidt         case I2C_SMBUS_BYTE_DATA:
7402864d58SJean Delvare 		buf = &data->byte;
7502864d58SJean Delvare 		len = 1;
76a28d3af2SBenjamin Herrenschmidt 	    	break;
77a28d3af2SBenjamin Herrenschmidt         case I2C_SMBUS_WORD_DATA:
78a28d3af2SBenjamin Herrenschmidt 		if (!read) {
79a28d3af2SBenjamin Herrenschmidt 			local[0] = data->word & 0xff;
80a28d3af2SBenjamin Herrenschmidt 			local[1] = (data->word >> 8) & 0xff;
81a28d3af2SBenjamin Herrenschmidt 		}
8202864d58SJean Delvare 		buf = local;
8302864d58SJean Delvare 		len = 2;
84a28d3af2SBenjamin Herrenschmidt 	    	break;
85a28d3af2SBenjamin Herrenschmidt 
86a28d3af2SBenjamin Herrenschmidt 	/* Note that these are broken vs. the expected smbus API where
8796acafe0SJoe Perches 	 * on reads, the length is actually returned from the function,
88a28d3af2SBenjamin Herrenschmidt 	 * but I think the current API makes no sense and I don't want
89a28d3af2SBenjamin Herrenschmidt 	 * any driver that I haven't verified for correctness to go
90a28d3af2SBenjamin Herrenschmidt 	 * anywhere near a pmac i2c bus anyway ...
91a28d3af2SBenjamin Herrenschmidt 	 *
92a28d3af2SBenjamin Herrenschmidt 	 * I'm also not completely sure what kind of phases to do between
93a28d3af2SBenjamin Herrenschmidt 	 * the actual command and the data (what I am _supposed_ to do that
94a28d3af2SBenjamin Herrenschmidt 	 * is). For now, I assume writes are a single stream and reads have
95a28d3af2SBenjamin Herrenschmidt 	 * a repeat start/addr phase (but not stop in between)
96a28d3af2SBenjamin Herrenschmidt 	 */
97a28d3af2SBenjamin Herrenschmidt         case I2C_SMBUS_BLOCK_DATA:
9802864d58SJean Delvare 		buf = data->block;
9902864d58SJean Delvare 		len = data->block[0] + 1;
100a28d3af2SBenjamin Herrenschmidt 		break;
101a28d3af2SBenjamin Herrenschmidt 	case I2C_SMBUS_I2C_BLOCK_DATA:
10202864d58SJean Delvare 		buf = &data->block[1];
10302864d58SJean Delvare 		len = data->block[0];
104a28d3af2SBenjamin Herrenschmidt 		break;
105a28d3af2SBenjamin Herrenschmidt 
106a28d3af2SBenjamin Herrenschmidt         default:
10702864d58SJean Delvare 		return -EINVAL;
108a28d3af2SBenjamin Herrenschmidt 	}
10902864d58SJean Delvare 
11002864d58SJean Delvare 	rc = pmac_i2c_open(bus, 0);
111d7d838a6SJean Delvare 	if (rc) {
112d7d838a6SJean Delvare 		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
11302864d58SJean Delvare 		return rc;
114d7d838a6SJean Delvare 	}
11502864d58SJean Delvare 
11602864d58SJean Delvare 	rc = pmac_i2c_setmode(bus, mode);
117d7d838a6SJean Delvare 	if (rc) {
118d7d838a6SJean Delvare 		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
119d7d838a6SJean Delvare 			mode, rc);
12002864d58SJean Delvare 		goto bail;
121d7d838a6SJean Delvare 	}
12202864d58SJean Delvare 
12302864d58SJean Delvare 	rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
124d7d838a6SJean Delvare 	if (rc) {
1258e4b980cSJean Delvare 		if (rc == -ENXIO)
1268e4b980cSJean Delvare 			dev_dbg(&adap->dev,
1278e4b980cSJean Delvare 				"I2C transfer at 0x%02x failed, size %d, "
1288e4b980cSJean Delvare 				"err %d\n", addrdir >> 1, size, rc);
1298e4b980cSJean Delvare 		else
130d7d838a6SJean Delvare 			dev_err(&adap->dev,
1318e4b980cSJean Delvare 				"I2C transfer at 0x%02x failed, size %d, "
1328e4b980cSJean Delvare 				"err %d\n", addrdir >> 1, size, rc);
13302864d58SJean Delvare 		goto bail;
134d7d838a6SJean Delvare 	}
13502864d58SJean Delvare 
13602864d58SJean Delvare 	if (size == I2C_SMBUS_WORD_DATA && read) {
13702864d58SJean Delvare 		data->word = ((u16)local[1]) << 8;
13802864d58SJean Delvare 		data->word |= local[0];
13902864d58SJean Delvare 	}
14002864d58SJean Delvare 
141a28d3af2SBenjamin Herrenschmidt  bail:
142a28d3af2SBenjamin Herrenschmidt 	pmac_i2c_close(bus);
143a28d3af2SBenjamin Herrenschmidt 	return rc;
144a28d3af2SBenjamin Herrenschmidt }
145a28d3af2SBenjamin Herrenschmidt 
146a28d3af2SBenjamin Herrenschmidt /*
147a28d3af2SBenjamin Herrenschmidt  * Generic i2c master transfer entrypoint. This driver only support single
148a28d3af2SBenjamin Herrenschmidt  * messages (for "lame i2c" transfers). Anything else should use the smbus
149a28d3af2SBenjamin Herrenschmidt  * entry point
150a28d3af2SBenjamin Herrenschmidt  */
151a28d3af2SBenjamin Herrenschmidt static int i2c_powermac_master_xfer(	struct i2c_adapter *adap,
152a28d3af2SBenjamin Herrenschmidt 					struct i2c_msg *msgs,
153a28d3af2SBenjamin Herrenschmidt 					int num)
154a28d3af2SBenjamin Herrenschmidt {
155a28d3af2SBenjamin Herrenschmidt 	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
156a28d3af2SBenjamin Herrenschmidt 	int			rc = 0;
157a28d3af2SBenjamin Herrenschmidt 	int			read;
158a28d3af2SBenjamin Herrenschmidt 	int			addrdir;
159a28d3af2SBenjamin Herrenschmidt 
1606f7e549fSJean Delvare 	if (num != 1) {
1616f7e549fSJean Delvare 		dev_err(&adap->dev,
1626f7e549fSJean Delvare 			"Multi-message I2C transactions not supported\n");
1636f7e549fSJean Delvare 		return -EOPNOTSUPP;
1646f7e549fSJean Delvare 	}
1656f7e549fSJean Delvare 
166a28d3af2SBenjamin Herrenschmidt 	if (msgs->flags & I2C_M_TEN)
167a28d3af2SBenjamin Herrenschmidt 		return -EINVAL;
168a28d3af2SBenjamin Herrenschmidt 	read = (msgs->flags & I2C_M_RD) != 0;
169a28d3af2SBenjamin Herrenschmidt 	addrdir = (msgs->addr << 1) | read;
170a28d3af2SBenjamin Herrenschmidt 
171a28d3af2SBenjamin Herrenschmidt 	rc = pmac_i2c_open(bus, 0);
172d7d838a6SJean Delvare 	if (rc) {
173d7d838a6SJean Delvare 		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
174a28d3af2SBenjamin Herrenschmidt 		return rc;
175d7d838a6SJean Delvare 	}
176a28d3af2SBenjamin Herrenschmidt 	rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
177d7d838a6SJean Delvare 	if (rc) {
178d7d838a6SJean Delvare 		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
179d7d838a6SJean Delvare 			pmac_i2c_mode_std, rc);
180a28d3af2SBenjamin Herrenschmidt 		goto bail;
181d7d838a6SJean Delvare 	}
182a28d3af2SBenjamin Herrenschmidt 	rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
1838e4b980cSJean Delvare 	if (rc < 0) {
1848e4b980cSJean Delvare 		if (rc == -ENXIO)
1858e4b980cSJean Delvare 			dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
1868e4b980cSJean Delvare 				addrdir & 1 ? "read from" : "write to",
1878e4b980cSJean Delvare 				addrdir >> 1, rc);
1888e4b980cSJean Delvare 		else
189d7d838a6SJean Delvare 			dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
1908e4b980cSJean Delvare 				addrdir & 1 ? "read from" : "write to",
1918e4b980cSJean Delvare 				addrdir >> 1, rc);
1928e4b980cSJean Delvare 	}
193a28d3af2SBenjamin Herrenschmidt  bail:
194a28d3af2SBenjamin Herrenschmidt 	pmac_i2c_close(bus);
1958ced8eeeSJean Delvare 	return rc < 0 ? rc : 1;
196a28d3af2SBenjamin Herrenschmidt }
197a28d3af2SBenjamin Herrenschmidt 
198a28d3af2SBenjamin Herrenschmidt static u32 i2c_powermac_func(struct i2c_adapter * adapter)
199a28d3af2SBenjamin Herrenschmidt {
200a28d3af2SBenjamin Herrenschmidt 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
201a28d3af2SBenjamin Herrenschmidt 		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
202a28d3af2SBenjamin Herrenschmidt 		I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
203a28d3af2SBenjamin Herrenschmidt }
204a28d3af2SBenjamin Herrenschmidt 
205a28d3af2SBenjamin Herrenschmidt /* For now, we only handle smbus */
2068f9082c5SJean Delvare static const struct i2c_algorithm i2c_powermac_algorithm = {
207a28d3af2SBenjamin Herrenschmidt 	.smbus_xfer	= i2c_powermac_smbus_xfer,
208a28d3af2SBenjamin Herrenschmidt 	.master_xfer	= i2c_powermac_master_xfer,
209a28d3af2SBenjamin Herrenschmidt 	.functionality	= i2c_powermac_func,
210a28d3af2SBenjamin Herrenschmidt };
211a28d3af2SBenjamin Herrenschmidt 
212a28d3af2SBenjamin Herrenschmidt 
2134ebb52d3SUwe Kleine-Koenig static int __devexit i2c_powermac_remove(struct platform_device *dev)
214a28d3af2SBenjamin Herrenschmidt {
2159f2545c1SBenjamin Herrenschmidt 	struct i2c_adapter	*adapter = platform_get_drvdata(dev);
216a28d3af2SBenjamin Herrenschmidt 	int			rc;
217a28d3af2SBenjamin Herrenschmidt 
218a28d3af2SBenjamin Herrenschmidt 	rc = i2c_del_adapter(adapter);
219a28d3af2SBenjamin Herrenschmidt 	/* We aren't that prepared to deal with this... */
220a28d3af2SBenjamin Herrenschmidt 	if (rc)
221154d22b0SFrank Seidel 		printk(KERN_WARNING
222154d22b0SFrank Seidel 		       "i2c-powermac.c: Failed to remove bus %s !\n",
223a28d3af2SBenjamin Herrenschmidt 		       adapter->name);
2249f2545c1SBenjamin Herrenschmidt 	platform_set_drvdata(dev, NULL);
2256dfa5ca3SJean Delvare 	memset(adapter, 0, sizeof(*adapter));
226a28d3af2SBenjamin Herrenschmidt 
227a28d3af2SBenjamin Herrenschmidt 	return 0;
228a28d3af2SBenjamin Herrenschmidt }
229a28d3af2SBenjamin Herrenschmidt 
230*3a3dd018SBenjamin Herrenschmidt static u32 __devinit i2c_powermac_get_addr(struct i2c_adapter *adap,
231*3a3dd018SBenjamin Herrenschmidt 					   struct pmac_i2c_bus *bus,
232*3a3dd018SBenjamin Herrenschmidt 					   struct device_node *node)
23381e5d864SBenjamin Herrenschmidt {
234*3a3dd018SBenjamin Herrenschmidt 	const __be32 *prop;
23581e5d864SBenjamin Herrenschmidt 	int len;
23681e5d864SBenjamin Herrenschmidt 
237*3a3dd018SBenjamin Herrenschmidt 	/* First check for valid "reg" */
238*3a3dd018SBenjamin Herrenschmidt 	prop = of_get_property(node, "reg", &len);
239*3a3dd018SBenjamin Herrenschmidt 	if (prop && (len >= sizeof(int)))
240*3a3dd018SBenjamin Herrenschmidt 		return (be32_to_cpup(prop) & 0xff) >> 1;
241*3a3dd018SBenjamin Herrenschmidt 
242*3a3dd018SBenjamin Herrenschmidt 	/* Then check old-style "i2c-address" */
243*3a3dd018SBenjamin Herrenschmidt 	prop = of_get_property(node, "i2c-address", &len);
244*3a3dd018SBenjamin Herrenschmidt 	if (prop && (len >= sizeof(int)))
245*3a3dd018SBenjamin Herrenschmidt 		return (be32_to_cpup(prop) & 0xff) >> 1;
246*3a3dd018SBenjamin Herrenschmidt 
247*3a3dd018SBenjamin Herrenschmidt 	/* Now handle some devices with missing "reg" properties */
248*3a3dd018SBenjamin Herrenschmidt 	if (!strcmp(node->name, "cereal"))
249*3a3dd018SBenjamin Herrenschmidt 		return 0x60;
250*3a3dd018SBenjamin Herrenschmidt 	else if (!strcmp(node->name, "deq"))
251*3a3dd018SBenjamin Herrenschmidt 		return 0x34;
252*3a3dd018SBenjamin Herrenschmidt 
253*3a3dd018SBenjamin Herrenschmidt 	dev_warn(&adap->dev, "No i2c address for %s\n", node->full_name);
254*3a3dd018SBenjamin Herrenschmidt 
255*3a3dd018SBenjamin Herrenschmidt 	return 0xffffffff;
25681e5d864SBenjamin Herrenschmidt }
25781e5d864SBenjamin Herrenschmidt 
258*3a3dd018SBenjamin Herrenschmidt static void __devinit i2c_powermac_create_one(struct i2c_adapter *adap,
259*3a3dd018SBenjamin Herrenschmidt 					      const char *type,
260*3a3dd018SBenjamin Herrenschmidt 					      u32 addr)
261*3a3dd018SBenjamin Herrenschmidt {
262*3a3dd018SBenjamin Herrenschmidt 	struct i2c_board_info info = {};
263*3a3dd018SBenjamin Herrenschmidt 	struct i2c_client *newdev;
26481e5d864SBenjamin Herrenschmidt 
265*3a3dd018SBenjamin Herrenschmidt 	strncpy(info.type, type, sizeof(info.type));
266*3a3dd018SBenjamin Herrenschmidt 	info.addr = addr;
267*3a3dd018SBenjamin Herrenschmidt 	newdev = i2c_new_device(adap, &info);
268*3a3dd018SBenjamin Herrenschmidt 	if (!newdev)
269*3a3dd018SBenjamin Herrenschmidt 		dev_err(&adap->dev,
270*3a3dd018SBenjamin Herrenschmidt 			"i2c-powermac: Failure to register missing %s\n",
271*3a3dd018SBenjamin Herrenschmidt 			type);
272*3a3dd018SBenjamin Herrenschmidt }
27381e5d864SBenjamin Herrenschmidt 
274*3a3dd018SBenjamin Herrenschmidt static void __devinit i2c_powermac_add_missing(struct i2c_adapter *adap,
275*3a3dd018SBenjamin Herrenschmidt 					       struct pmac_i2c_bus *bus,
276*3a3dd018SBenjamin Herrenschmidt 					       bool found_onyx)
277*3a3dd018SBenjamin Herrenschmidt {
278*3a3dd018SBenjamin Herrenschmidt 	struct device_node *busnode = pmac_i2c_get_bus_node(bus);
279*3a3dd018SBenjamin Herrenschmidt 	int rc;
280*3a3dd018SBenjamin Herrenschmidt 
281*3a3dd018SBenjamin Herrenschmidt 	/* Check for the onyx audio codec */
282*3a3dd018SBenjamin Herrenschmidt #define ONYX_REG_CONTROL		67
283*3a3dd018SBenjamin Herrenschmidt 	if (of_device_is_compatible(busnode, "k2-i2c") && !found_onyx) {
284*3a3dd018SBenjamin Herrenschmidt 		union i2c_smbus_data data;
285*3a3dd018SBenjamin Herrenschmidt 
286*3a3dd018SBenjamin Herrenschmidt 		rc = i2c_smbus_xfer(adap, 0x46, 0, I2C_SMBUS_READ,
287*3a3dd018SBenjamin Herrenschmidt 				    ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,
288*3a3dd018SBenjamin Herrenschmidt 				    &data);
289*3a3dd018SBenjamin Herrenschmidt 		if (rc >= 0)
290*3a3dd018SBenjamin Herrenschmidt 			i2c_powermac_create_one(adap, "MAC,pcm3052", 0x46);
291*3a3dd018SBenjamin Herrenschmidt 
292*3a3dd018SBenjamin Herrenschmidt 		rc = i2c_smbus_xfer(adap, 0x47, 0, I2C_SMBUS_READ,
293*3a3dd018SBenjamin Herrenschmidt 				    ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,
294*3a3dd018SBenjamin Herrenschmidt 				    &data);
295*3a3dd018SBenjamin Herrenschmidt 		if (rc >= 0)
296*3a3dd018SBenjamin Herrenschmidt 			i2c_powermac_create_one(adap, "MAC,pcm3052", 0x47);
297*3a3dd018SBenjamin Herrenschmidt 	}
298*3a3dd018SBenjamin Herrenschmidt }
299*3a3dd018SBenjamin Herrenschmidt 
300*3a3dd018SBenjamin Herrenschmidt static bool __devinit i2c_powermac_get_type(struct i2c_adapter *adap,
301*3a3dd018SBenjamin Herrenschmidt 					    struct device_node *node,
302*3a3dd018SBenjamin Herrenschmidt 					    u32 addr, char *type, int type_size)
303*3a3dd018SBenjamin Herrenschmidt {
304*3a3dd018SBenjamin Herrenschmidt 	char tmp[16];
305*3a3dd018SBenjamin Herrenschmidt 
306*3a3dd018SBenjamin Herrenschmidt 	/* Note: we to _NOT_ want the standard
30781e5d864SBenjamin Herrenschmidt 	 * i2c drivers to match with any of our powermac stuff
30881e5d864SBenjamin Herrenschmidt 	 * unless they have been specifically modified to handle
30981e5d864SBenjamin Herrenschmidt 	 * it on a case by case basis. For example, for thermal
31081e5d864SBenjamin Herrenschmidt 	 * control, things like lm75 etc... shall match with their
31181e5d864SBenjamin Herrenschmidt 	 * corresponding windfarm drivers, _NOT_ the generic ones,
31281e5d864SBenjamin Herrenschmidt 	 * so we force a prefix of AAPL, onto the modalias to
31381e5d864SBenjamin Herrenschmidt 	 * make that happen
31481e5d864SBenjamin Herrenschmidt 	 */
315*3a3dd018SBenjamin Herrenschmidt 
316*3a3dd018SBenjamin Herrenschmidt 	/* First try proper modalias */
317*3a3dd018SBenjamin Herrenschmidt 	if (of_modalias_node(node, tmp, sizeof(tmp)) >= 0) {
318*3a3dd018SBenjamin Herrenschmidt 		snprintf(type, type_size, "MAC,%s", tmp);
319*3a3dd018SBenjamin Herrenschmidt 		return true;
320*3a3dd018SBenjamin Herrenschmidt 	}
321*3a3dd018SBenjamin Herrenschmidt 
322*3a3dd018SBenjamin Herrenschmidt 	/* Now look for known workarounds */
323*3a3dd018SBenjamin Herrenschmidt 	if (!strcmp(node->name, "deq")) {
324*3a3dd018SBenjamin Herrenschmidt 		/* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
325*3a3dd018SBenjamin Herrenschmidt 		if (addr == 0x34) {
326*3a3dd018SBenjamin Herrenschmidt 			snprintf(type, type_size, "MAC,tas3001");
327*3a3dd018SBenjamin Herrenschmidt 			return true;
328*3a3dd018SBenjamin Herrenschmidt 		} else if (addr == 0x35) {
329*3a3dd018SBenjamin Herrenschmidt 			snprintf(type, type_size, "MAC,tas3004");
330*3a3dd018SBenjamin Herrenschmidt 			return true;
331*3a3dd018SBenjamin Herrenschmidt 		}
332*3a3dd018SBenjamin Herrenschmidt 	}
333*3a3dd018SBenjamin Herrenschmidt 
33481e5d864SBenjamin Herrenschmidt 	dev_err(&adap->dev, "i2c-powermac: modalias failure"
33581e5d864SBenjamin Herrenschmidt 		" on %s\n", node->full_name);
336*3a3dd018SBenjamin Herrenschmidt 	return false;
337*3a3dd018SBenjamin Herrenschmidt }
338*3a3dd018SBenjamin Herrenschmidt 
339*3a3dd018SBenjamin Herrenschmidt static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
340*3a3dd018SBenjamin Herrenschmidt 						    struct pmac_i2c_bus *bus)
341*3a3dd018SBenjamin Herrenschmidt {
342*3a3dd018SBenjamin Herrenschmidt 	struct i2c_client *newdev;
343*3a3dd018SBenjamin Herrenschmidt 	struct device_node *node;
344*3a3dd018SBenjamin Herrenschmidt 	bool found_onyx = 0;
345*3a3dd018SBenjamin Herrenschmidt 
346*3a3dd018SBenjamin Herrenschmidt 	/*
347*3a3dd018SBenjamin Herrenschmidt 	 * In some cases we end up with the via-pmu node itself, in this
348*3a3dd018SBenjamin Herrenschmidt 	 * case we skip this function completely as the device-tree will
349*3a3dd018SBenjamin Herrenschmidt 	 * not contain anything useful.
350*3a3dd018SBenjamin Herrenschmidt 	 */
351*3a3dd018SBenjamin Herrenschmidt 	if (!strcmp(adap->dev.of_node->name, "via-pmu"))
352*3a3dd018SBenjamin Herrenschmidt 		return;
353*3a3dd018SBenjamin Herrenschmidt 
354*3a3dd018SBenjamin Herrenschmidt 	for_each_child_of_node(adap->dev.of_node, node) {
355*3a3dd018SBenjamin Herrenschmidt 		struct i2c_board_info info = {};
356*3a3dd018SBenjamin Herrenschmidt 		u32 addr;
357*3a3dd018SBenjamin Herrenschmidt 
358*3a3dd018SBenjamin Herrenschmidt 		/* Get address & channel */
359*3a3dd018SBenjamin Herrenschmidt 		addr = i2c_powermac_get_addr(adap, bus, node);
360*3a3dd018SBenjamin Herrenschmidt 		if (addr == 0xffffffff)
361*3a3dd018SBenjamin Herrenschmidt 			continue;
362*3a3dd018SBenjamin Herrenschmidt 
363*3a3dd018SBenjamin Herrenschmidt 		/* Multibus setup, check channel */
364*3a3dd018SBenjamin Herrenschmidt 		if (!pmac_i2c_match_adapter(node, adap))
365*3a3dd018SBenjamin Herrenschmidt 			continue;
366*3a3dd018SBenjamin Herrenschmidt 
367*3a3dd018SBenjamin Herrenschmidt 		dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
368*3a3dd018SBenjamin Herrenschmidt 			node->full_name);
369*3a3dd018SBenjamin Herrenschmidt 
370*3a3dd018SBenjamin Herrenschmidt 		/*
371*3a3dd018SBenjamin Herrenschmidt 		 * Keep track of some device existence to handle
372*3a3dd018SBenjamin Herrenschmidt 		 * workarounds later.
373*3a3dd018SBenjamin Herrenschmidt 		 */
374*3a3dd018SBenjamin Herrenschmidt 		if (of_device_is_compatible(node, "pcm3052"))
375*3a3dd018SBenjamin Herrenschmidt 			found_onyx = true;
376*3a3dd018SBenjamin Herrenschmidt 
377*3a3dd018SBenjamin Herrenschmidt 		/* Make up a modalias */
378*3a3dd018SBenjamin Herrenschmidt 		if (!i2c_powermac_get_type(adap, node, addr,
379*3a3dd018SBenjamin Herrenschmidt 					   info.type, sizeof(info.type))) {
38081e5d864SBenjamin Herrenschmidt 			continue;
38181e5d864SBenjamin Herrenschmidt 		}
38281e5d864SBenjamin Herrenschmidt 
38381e5d864SBenjamin Herrenschmidt 		/* Fill out the rest of the info structure */
384*3a3dd018SBenjamin Herrenschmidt 		info.addr = addr;
38581e5d864SBenjamin Herrenschmidt 		info.irq = irq_of_parse_and_map(node, 0);
38681e5d864SBenjamin Herrenschmidt 		info.of_node = of_node_get(node);
38781e5d864SBenjamin Herrenschmidt 
38881e5d864SBenjamin Herrenschmidt 		newdev = i2c_new_device(adap, &info);
38981e5d864SBenjamin Herrenschmidt 		if (!newdev) {
39081e5d864SBenjamin Herrenschmidt 			dev_err(&adap->dev, "i2c-powermac: Failure to register"
39181e5d864SBenjamin Herrenschmidt 				" %s\n", node->full_name);
39281e5d864SBenjamin Herrenschmidt 			of_node_put(node);
39381e5d864SBenjamin Herrenschmidt 			/* We do not dispose of the interrupt mapping on
39481e5d864SBenjamin Herrenschmidt 			 * purpose. It's not necessary (interrupt cannot be
39581e5d864SBenjamin Herrenschmidt 			 * re-used) and somebody else might have grabbed it
39681e5d864SBenjamin Herrenschmidt 			 * via direct DT lookup so let's not bother
39781e5d864SBenjamin Herrenschmidt 			 */
39881e5d864SBenjamin Herrenschmidt 			continue;
39981e5d864SBenjamin Herrenschmidt 		}
40081e5d864SBenjamin Herrenschmidt 	}
401*3a3dd018SBenjamin Herrenschmidt 
402*3a3dd018SBenjamin Herrenschmidt 	/* Additional workarounds */
403*3a3dd018SBenjamin Herrenschmidt 	i2c_powermac_add_missing(adap, bus, found_onyx);
40481e5d864SBenjamin Herrenschmidt }
405a28d3af2SBenjamin Herrenschmidt 
4064ebb52d3SUwe Kleine-Koenig static int __devinit i2c_powermac_probe(struct platform_device *dev)
407a28d3af2SBenjamin Herrenschmidt {
4089f2545c1SBenjamin Herrenschmidt 	struct pmac_i2c_bus *bus = dev->dev.platform_data;
409a28d3af2SBenjamin Herrenschmidt 	struct device_node *parent = NULL;
410a28d3af2SBenjamin Herrenschmidt 	struct i2c_adapter *adapter;
411018a3d1dSJeremy Kerr 	const char *basename;
412a28d3af2SBenjamin Herrenschmidt 	int rc;
413a28d3af2SBenjamin Herrenschmidt 
414a28d3af2SBenjamin Herrenschmidt 	if (bus == NULL)
415a28d3af2SBenjamin Herrenschmidt 		return -EINVAL;
416bc6286e5SJean Delvare 	adapter = pmac_i2c_get_adapter(bus);
417a28d3af2SBenjamin Herrenschmidt 
418a28d3af2SBenjamin Herrenschmidt 	/* Ok, now we need to make up a name for the interface that will
419a28d3af2SBenjamin Herrenschmidt 	 * match what we used to do in the past, that is basically the
420a28d3af2SBenjamin Herrenschmidt 	 * controller's parent device node for keywest. PMU didn't have a
421a28d3af2SBenjamin Herrenschmidt 	 * naming convention and SMU has a different one
422a28d3af2SBenjamin Herrenschmidt 	 */
423a28d3af2SBenjamin Herrenschmidt 	switch(pmac_i2c_get_type(bus)) {
424a28d3af2SBenjamin Herrenschmidt 	case pmac_i2c_bus_keywest:
425a28d3af2SBenjamin Herrenschmidt 		parent = of_get_parent(pmac_i2c_get_controller(bus));
426a28d3af2SBenjamin Herrenschmidt 		if (parent == NULL)
427a28d3af2SBenjamin Herrenschmidt 			return -EINVAL;
428a28d3af2SBenjamin Herrenschmidt 		basename = parent->name;
429a28d3af2SBenjamin Herrenschmidt 		break;
430a28d3af2SBenjamin Herrenschmidt 	case pmac_i2c_bus_pmu:
431a28d3af2SBenjamin Herrenschmidt 		basename = "pmu";
432a28d3af2SBenjamin Herrenschmidt 		break;
433a28d3af2SBenjamin Herrenschmidt 	case pmac_i2c_bus_smu:
434a28d3af2SBenjamin Herrenschmidt 		/* This is not what we used to do but I'm fixing drivers at
435a28d3af2SBenjamin Herrenschmidt 		 * the same time as this change
436a28d3af2SBenjamin Herrenschmidt 		 */
437a28d3af2SBenjamin Herrenschmidt 		basename = "smu";
438a28d3af2SBenjamin Herrenschmidt 		break;
439a28d3af2SBenjamin Herrenschmidt 	default:
440a28d3af2SBenjamin Herrenschmidt 		return -EINVAL;
441a28d3af2SBenjamin Herrenschmidt 	}
442bc6286e5SJean Delvare 	snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
443bc6286e5SJean Delvare 		 pmac_i2c_get_channel(bus));
444a28d3af2SBenjamin Herrenschmidt 	of_node_put(parent);
445a28d3af2SBenjamin Herrenschmidt 
4469f2545c1SBenjamin Herrenschmidt 	platform_set_drvdata(dev, adapter);
447a28d3af2SBenjamin Herrenschmidt 	adapter->algo = &i2c_powermac_algorithm;
448a28d3af2SBenjamin Herrenschmidt 	i2c_set_adapdata(adapter, bus);
4499f2545c1SBenjamin Herrenschmidt 	adapter->dev.parent = &dev->dev;
45081e5d864SBenjamin Herrenschmidt 	adapter->dev.of_node = dev->dev.of_node;
451a28d3af2SBenjamin Herrenschmidt 	rc = i2c_add_adapter(adapter);
452a28d3af2SBenjamin Herrenschmidt 	if (rc) {
453a28d3af2SBenjamin Herrenschmidt 		printk(KERN_ERR "i2c-powermac: Adapter %s registration "
454bc6286e5SJean Delvare 		       "failed\n", adapter->name);
4556dfa5ca3SJean Delvare 		memset(adapter, 0, sizeof(*adapter));
456a28d3af2SBenjamin Herrenschmidt 	}
457a28d3af2SBenjamin Herrenschmidt 
458bc6286e5SJean Delvare 	printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
459810ad7b6SJean Delvare 
46081e5d864SBenjamin Herrenschmidt 	/* Cannot use of_i2c_register_devices() due to Apple device-tree
46181e5d864SBenjamin Herrenschmidt 	 * funkyness
46281e5d864SBenjamin Herrenschmidt 	 */
46381e5d864SBenjamin Herrenschmidt 	i2c_powermac_register_devices(adapter, bus);
464810ad7b6SJean Delvare 
465a28d3af2SBenjamin Herrenschmidt 	return rc;
466a28d3af2SBenjamin Herrenschmidt }
467a28d3af2SBenjamin Herrenschmidt 
4689f2545c1SBenjamin Herrenschmidt static struct platform_driver i2c_powermac_driver = {
4699f2545c1SBenjamin Herrenschmidt 	.probe = i2c_powermac_probe,
4709f2545c1SBenjamin Herrenschmidt 	.remove = __devexit_p(i2c_powermac_remove),
4719f2545c1SBenjamin Herrenschmidt 	.driver = {
472a28d3af2SBenjamin Herrenschmidt 		.name = "i2c-powermac",
473a28d3af2SBenjamin Herrenschmidt 		.bus = &platform_bus_type,
4749f2545c1SBenjamin Herrenschmidt 	},
475a28d3af2SBenjamin Herrenschmidt };
476a28d3af2SBenjamin Herrenschmidt 
477a3664b51SAxel Lin module_platform_driver(i2c_powermac_driver);
478a28d3af2SBenjamin Herrenschmidt 
479a3664b51SAxel Lin MODULE_ALIAS("platform:i2c-powermac");
480