xref: /openbmc/linux/drivers/i2c/busses/i2c-powermac.c (revision 6dfa5ca3c9a35cb395ab1f51e0e500106c85dff4)
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) {
125d7d838a6SJean Delvare 		dev_err(&adap->dev,
126d7d838a6SJean Delvare 			"I2C transfer at 0x%02x failed, size %d, err %d\n",
127d7d838a6SJean Delvare 			addrdir >> 1, size, rc);
12802864d58SJean Delvare 		goto bail;
129d7d838a6SJean Delvare 	}
13002864d58SJean Delvare 
13102864d58SJean Delvare 	if (size == I2C_SMBUS_WORD_DATA && read) {
13202864d58SJean Delvare 		data->word = ((u16)local[1]) << 8;
13302864d58SJean Delvare 		data->word |= local[0];
13402864d58SJean Delvare 	}
13502864d58SJean Delvare 
136a28d3af2SBenjamin Herrenschmidt  bail:
137a28d3af2SBenjamin Herrenschmidt 	pmac_i2c_close(bus);
138a28d3af2SBenjamin Herrenschmidt 	return rc;
139a28d3af2SBenjamin Herrenschmidt }
140a28d3af2SBenjamin Herrenschmidt 
141a28d3af2SBenjamin Herrenschmidt /*
142a28d3af2SBenjamin Herrenschmidt  * Generic i2c master transfer entrypoint. This driver only support single
143a28d3af2SBenjamin Herrenschmidt  * messages (for "lame i2c" transfers). Anything else should use the smbus
144a28d3af2SBenjamin Herrenschmidt  * entry point
145a28d3af2SBenjamin Herrenschmidt  */
146a28d3af2SBenjamin Herrenschmidt static int i2c_powermac_master_xfer(	struct i2c_adapter *adap,
147a28d3af2SBenjamin Herrenschmidt 					struct i2c_msg *msgs,
148a28d3af2SBenjamin Herrenschmidt 					int num)
149a28d3af2SBenjamin Herrenschmidt {
150a28d3af2SBenjamin Herrenschmidt 	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
151a28d3af2SBenjamin Herrenschmidt 	int			rc = 0;
152a28d3af2SBenjamin Herrenschmidt 	int			read;
153a28d3af2SBenjamin Herrenschmidt 	int			addrdir;
154a28d3af2SBenjamin Herrenschmidt 
1556f7e549fSJean Delvare 	if (num != 1) {
1566f7e549fSJean Delvare 		dev_err(&adap->dev,
1576f7e549fSJean Delvare 			"Multi-message I2C transactions not supported\n");
1586f7e549fSJean Delvare 		return -EOPNOTSUPP;
1596f7e549fSJean Delvare 	}
1606f7e549fSJean Delvare 
161a28d3af2SBenjamin Herrenschmidt 	if (msgs->flags & I2C_M_TEN)
162a28d3af2SBenjamin Herrenschmidt 		return -EINVAL;
163a28d3af2SBenjamin Herrenschmidt 	read = (msgs->flags & I2C_M_RD) != 0;
164a28d3af2SBenjamin Herrenschmidt 	addrdir = (msgs->addr << 1) | read;
165a28d3af2SBenjamin Herrenschmidt 	if (msgs->flags & I2C_M_REV_DIR_ADDR)
166a28d3af2SBenjamin Herrenschmidt 		addrdir ^= 1;
167a28d3af2SBenjamin Herrenschmidt 
168a28d3af2SBenjamin Herrenschmidt 	rc = pmac_i2c_open(bus, 0);
169d7d838a6SJean Delvare 	if (rc) {
170d7d838a6SJean Delvare 		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
171a28d3af2SBenjamin Herrenschmidt 		return rc;
172d7d838a6SJean Delvare 	}
173a28d3af2SBenjamin Herrenschmidt 	rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
174d7d838a6SJean Delvare 	if (rc) {
175d7d838a6SJean Delvare 		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
176d7d838a6SJean Delvare 			pmac_i2c_mode_std, rc);
177a28d3af2SBenjamin Herrenschmidt 		goto bail;
178d7d838a6SJean Delvare 	}
179a28d3af2SBenjamin Herrenschmidt 	rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
180d7d838a6SJean Delvare 	if (rc < 0)
181d7d838a6SJean Delvare 		dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
182d7d838a6SJean Delvare 			addrdir & 1 ? "read from" : "write to", addrdir >> 1,
183d7d838a6SJean Delvare 			rc);
184a28d3af2SBenjamin Herrenschmidt  bail:
185a28d3af2SBenjamin Herrenschmidt 	pmac_i2c_close(bus);
1868ced8eeeSJean Delvare 	return rc < 0 ? rc : 1;
187a28d3af2SBenjamin Herrenschmidt }
188a28d3af2SBenjamin Herrenschmidt 
189a28d3af2SBenjamin Herrenschmidt static u32 i2c_powermac_func(struct i2c_adapter * adapter)
190a28d3af2SBenjamin Herrenschmidt {
191a28d3af2SBenjamin Herrenschmidt 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
192a28d3af2SBenjamin Herrenschmidt 		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
193a28d3af2SBenjamin Herrenschmidt 		I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
194a28d3af2SBenjamin Herrenschmidt }
195a28d3af2SBenjamin Herrenschmidt 
196a28d3af2SBenjamin Herrenschmidt /* For now, we only handle smbus */
1978f9082c5SJean Delvare static const struct i2c_algorithm i2c_powermac_algorithm = {
198a28d3af2SBenjamin Herrenschmidt 	.smbus_xfer	= i2c_powermac_smbus_xfer,
199a28d3af2SBenjamin Herrenschmidt 	.master_xfer	= i2c_powermac_master_xfer,
200a28d3af2SBenjamin Herrenschmidt 	.functionality	= i2c_powermac_func,
201a28d3af2SBenjamin Herrenschmidt };
202a28d3af2SBenjamin Herrenschmidt 
203a28d3af2SBenjamin Herrenschmidt 
2044ebb52d3SUwe Kleine-Koenig static int __devexit i2c_powermac_remove(struct platform_device *dev)
205a28d3af2SBenjamin Herrenschmidt {
2069f2545c1SBenjamin Herrenschmidt 	struct i2c_adapter	*adapter = platform_get_drvdata(dev);
207a28d3af2SBenjamin Herrenschmidt 	int			rc;
208a28d3af2SBenjamin Herrenschmidt 
209a28d3af2SBenjamin Herrenschmidt 	rc = i2c_del_adapter(adapter);
210a28d3af2SBenjamin Herrenschmidt 	/* We aren't that prepared to deal with this... */
211a28d3af2SBenjamin Herrenschmidt 	if (rc)
212154d22b0SFrank Seidel 		printk(KERN_WARNING
213154d22b0SFrank Seidel 		       "i2c-powermac.c: Failed to remove bus %s !\n",
214a28d3af2SBenjamin Herrenschmidt 		       adapter->name);
2159f2545c1SBenjamin Herrenschmidt 	platform_set_drvdata(dev, NULL);
216*6dfa5ca3SJean Delvare 	memset(adapter, 0, sizeof(*adapter));
217a28d3af2SBenjamin Herrenschmidt 
218a28d3af2SBenjamin Herrenschmidt 	return 0;
219a28d3af2SBenjamin Herrenschmidt }
220a28d3af2SBenjamin Herrenschmidt 
221a28d3af2SBenjamin Herrenschmidt 
2224ebb52d3SUwe Kleine-Koenig static int __devinit i2c_powermac_probe(struct platform_device *dev)
223a28d3af2SBenjamin Herrenschmidt {
2249f2545c1SBenjamin Herrenschmidt 	struct pmac_i2c_bus *bus = dev->dev.platform_data;
225a28d3af2SBenjamin Herrenschmidt 	struct device_node *parent = NULL;
226a28d3af2SBenjamin Herrenschmidt 	struct i2c_adapter *adapter;
227018a3d1dSJeremy Kerr 	char name[32];
228018a3d1dSJeremy Kerr 	const char *basename;
229a28d3af2SBenjamin Herrenschmidt 	int rc;
230a28d3af2SBenjamin Herrenschmidt 
231a28d3af2SBenjamin Herrenschmidt 	if (bus == NULL)
232a28d3af2SBenjamin Herrenschmidt 		return -EINVAL;
233a28d3af2SBenjamin Herrenschmidt 
234a28d3af2SBenjamin Herrenschmidt 	/* Ok, now we need to make up a name for the interface that will
235a28d3af2SBenjamin Herrenschmidt 	 * match what we used to do in the past, that is basically the
236a28d3af2SBenjamin Herrenschmidt 	 * controller's parent device node for keywest. PMU didn't have a
237a28d3af2SBenjamin Herrenschmidt 	 * naming convention and SMU has a different one
238a28d3af2SBenjamin Herrenschmidt 	 */
239a28d3af2SBenjamin Herrenschmidt 	switch(pmac_i2c_get_type(bus)) {
240a28d3af2SBenjamin Herrenschmidt 	case pmac_i2c_bus_keywest:
241a28d3af2SBenjamin Herrenschmidt 		parent = of_get_parent(pmac_i2c_get_controller(bus));
242a28d3af2SBenjamin Herrenschmidt 		if (parent == NULL)
243a28d3af2SBenjamin Herrenschmidt 			return -EINVAL;
244a28d3af2SBenjamin Herrenschmidt 		basename = parent->name;
245a28d3af2SBenjamin Herrenschmidt 		break;
246a28d3af2SBenjamin Herrenschmidt 	case pmac_i2c_bus_pmu:
247a28d3af2SBenjamin Herrenschmidt 		basename = "pmu";
248a28d3af2SBenjamin Herrenschmidt 		break;
249a28d3af2SBenjamin Herrenschmidt 	case pmac_i2c_bus_smu:
250a28d3af2SBenjamin Herrenschmidt 		/* This is not what we used to do but I'm fixing drivers at
251a28d3af2SBenjamin Herrenschmidt 		 * the same time as this change
252a28d3af2SBenjamin Herrenschmidt 		 */
253a28d3af2SBenjamin Herrenschmidt 		basename = "smu";
254a28d3af2SBenjamin Herrenschmidt 		break;
255a28d3af2SBenjamin Herrenschmidt 	default:
256a28d3af2SBenjamin Herrenschmidt 		return -EINVAL;
257a28d3af2SBenjamin Herrenschmidt 	}
258a28d3af2SBenjamin Herrenschmidt 	snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus));
259a28d3af2SBenjamin Herrenschmidt 	of_node_put(parent);
260a28d3af2SBenjamin Herrenschmidt 
261*6dfa5ca3SJean Delvare 	adapter = pmac_i2c_get_adapter(bus);
2629f2545c1SBenjamin Herrenschmidt 	platform_set_drvdata(dev, adapter);
263a28d3af2SBenjamin Herrenschmidt 	strcpy(adapter->name, name);
264a28d3af2SBenjamin Herrenschmidt 	adapter->algo = &i2c_powermac_algorithm;
265a28d3af2SBenjamin Herrenschmidt 	i2c_set_adapdata(adapter, bus);
2669f2545c1SBenjamin Herrenschmidt 	adapter->dev.parent = &dev->dev;
267a28d3af2SBenjamin Herrenschmidt 	rc = i2c_add_adapter(adapter);
268a28d3af2SBenjamin Herrenschmidt 	if (rc) {
269a28d3af2SBenjamin Herrenschmidt 		printk(KERN_ERR "i2c-powermac: Adapter %s registration "
270a28d3af2SBenjamin Herrenschmidt 		       "failed\n", name);
271*6dfa5ca3SJean Delvare 		memset(adapter, 0, sizeof(*adapter));
272a28d3af2SBenjamin Herrenschmidt 	}
273a28d3af2SBenjamin Herrenschmidt 
274a28d3af2SBenjamin Herrenschmidt 	printk(KERN_INFO "PowerMac i2c bus %s registered\n", name);
275810ad7b6SJean Delvare 
276810ad7b6SJean Delvare 	if (!strncmp(basename, "uni-n", 5)) {
277810ad7b6SJean Delvare 		struct device_node *np;
278810ad7b6SJean Delvare 		const u32 *prop;
279810ad7b6SJean Delvare 		struct i2c_board_info info;
280810ad7b6SJean Delvare 
281810ad7b6SJean Delvare 		/* Instantiate I2C motion sensor if present */
282810ad7b6SJean Delvare 		np = of_find_node_by_name(NULL, "accelerometer");
283810ad7b6SJean Delvare 		if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
284810ad7b6SJean Delvare 		    (prop = of_get_property(np, "reg", NULL))) {
285810ad7b6SJean Delvare 			int i2c_bus;
286810ad7b6SJean Delvare 			const char *tmp_bus;
287810ad7b6SJean Delvare 
288810ad7b6SJean Delvare 			/* look for bus either using "reg" or by path */
289810ad7b6SJean Delvare 			tmp_bus = strstr(np->full_name, "/i2c-bus@");
290810ad7b6SJean Delvare 			if (tmp_bus)
291810ad7b6SJean Delvare 				i2c_bus = *(tmp_bus + 9) - '0';
292810ad7b6SJean Delvare 			else
293810ad7b6SJean Delvare 				i2c_bus = ((*prop) >> 8) & 0x0f;
294810ad7b6SJean Delvare 
295810ad7b6SJean Delvare 			if (pmac_i2c_get_channel(bus) == i2c_bus) {
296810ad7b6SJean Delvare 				memset(&info, 0, sizeof(struct i2c_board_info));
297810ad7b6SJean Delvare 				info.addr = ((*prop) & 0xff) >> 1;
298810ad7b6SJean Delvare 				strlcpy(info.type, "ams", I2C_NAME_SIZE);
299810ad7b6SJean Delvare 				i2c_new_device(adapter, &info);
300810ad7b6SJean Delvare 			}
301810ad7b6SJean Delvare 		}
302810ad7b6SJean Delvare 	}
303810ad7b6SJean Delvare 
304a28d3af2SBenjamin Herrenschmidt 	return rc;
305a28d3af2SBenjamin Herrenschmidt }
306a28d3af2SBenjamin Herrenschmidt 
307a28d3af2SBenjamin Herrenschmidt 
308add8eda7SKay Sievers /* work with hotplug and coldplug */
309add8eda7SKay Sievers MODULE_ALIAS("platform:i2c-powermac");
310add8eda7SKay Sievers 
3119f2545c1SBenjamin Herrenschmidt static struct platform_driver i2c_powermac_driver = {
3129f2545c1SBenjamin Herrenschmidt 	.probe = i2c_powermac_probe,
3139f2545c1SBenjamin Herrenschmidt 	.remove = __devexit_p(i2c_powermac_remove),
3149f2545c1SBenjamin Herrenschmidt 	.driver = {
315a28d3af2SBenjamin Herrenschmidt 		.name = "i2c-powermac",
316a28d3af2SBenjamin Herrenschmidt 		.bus = &platform_bus_type,
3179f2545c1SBenjamin Herrenschmidt 	},
318a28d3af2SBenjamin Herrenschmidt };
319a28d3af2SBenjamin Herrenschmidt 
320a28d3af2SBenjamin Herrenschmidt static int __init i2c_powermac_init(void)
321a28d3af2SBenjamin Herrenschmidt {
3229f2545c1SBenjamin Herrenschmidt 	platform_driver_register(&i2c_powermac_driver);
323a28d3af2SBenjamin Herrenschmidt 	return 0;
324a28d3af2SBenjamin Herrenschmidt }
325a28d3af2SBenjamin Herrenschmidt 
326a28d3af2SBenjamin Herrenschmidt 
327a28d3af2SBenjamin Herrenschmidt static void __exit i2c_powermac_cleanup(void)
328a28d3af2SBenjamin Herrenschmidt {
3299f2545c1SBenjamin Herrenschmidt 	platform_driver_unregister(&i2c_powermac_driver);
330a28d3af2SBenjamin Herrenschmidt }
331a28d3af2SBenjamin Herrenschmidt 
332a28d3af2SBenjamin Herrenschmidt module_init(i2c_powermac_init);
333a28d3af2SBenjamin Herrenschmidt module_exit(i2c_powermac_cleanup);
334