[PATCH] Owner field additions to many i2c drivers, 1 of 5
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / i2c / busses / i2c-pmac-smu.c
blob8a9f5648a23ddef2cfe80a5aea7841b6a583263f
1 /*
2 i2c Support for Apple SMU Controller
4 Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
5 <benh@kernel.crashing.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/types.h>
27 #include <linux/i2c.h>
28 #include <linux/init.h>
29 #include <linux/completion.h>
30 #include <linux/device.h>
31 #include <asm/prom.h>
32 #include <asm/of_device.h>
33 #include <asm/smu.h>
35 static int probe;
37 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
38 MODULE_DESCRIPTION("I2C driver for Apple's SMU");
39 MODULE_LICENSE("GPL");
40 module_param(probe, bool, 0);
43 /* Physical interface */
44 struct smu_iface
46 struct i2c_adapter adapter;
47 struct completion complete;
48 u32 busid;
51 static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc)
53 struct smu_iface *iface = misc;
54 complete(&iface->complete);
58 * SMBUS-type transfer entrypoint
60 static s32 smu_smbus_xfer( struct i2c_adapter* adap,
61 u16 addr,
62 unsigned short flags,
63 char read_write,
64 u8 command,
65 int size,
66 union i2c_smbus_data* data)
68 struct smu_iface *iface = i2c_get_adapdata(adap);
69 struct smu_i2c_cmd cmd;
70 int rc = 0;
71 int read = (read_write == I2C_SMBUS_READ);
73 cmd.info.bus = iface->busid;
74 cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00);
76 /* Prepare datas & select mode */
77 switch (size) {
78 case I2C_SMBUS_QUICK:
79 cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
80 cmd.info.datalen = 0;
81 break;
82 case I2C_SMBUS_BYTE:
83 cmd.info.type = SMU_I2C_TRANSFER_SIMPLE;
84 cmd.info.datalen = 1;
85 if (!read)
86 cmd.info.data[0] = data->byte;
87 break;
88 case I2C_SMBUS_BYTE_DATA:
89 cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
90 cmd.info.datalen = 1;
91 cmd.info.sublen = 1;
92 cmd.info.subaddr[0] = command;
93 cmd.info.subaddr[1] = 0;
94 cmd.info.subaddr[2] = 0;
95 if (!read)
96 cmd.info.data[0] = data->byte;
97 break;
98 case I2C_SMBUS_WORD_DATA:
99 cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
100 cmd.info.datalen = 2;
101 cmd.info.sublen = 1;
102 cmd.info.subaddr[0] = command;
103 cmd.info.subaddr[1] = 0;
104 cmd.info.subaddr[2] = 0;
105 if (!read) {
106 cmd.info.data[0] = data->byte & 0xff;
107 cmd.info.data[1] = (data->byte >> 8) & 0xff;
109 break;
110 /* Note that these are broken vs. the expected smbus API where
111 * on reads, the lenght is actually returned from the function,
112 * but I think the current API makes no sense and I don't want
113 * any driver that I haven't verified for correctness to go
114 * anywhere near a pmac i2c bus anyway ...
116 case I2C_SMBUS_BLOCK_DATA:
117 cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
118 cmd.info.datalen = data->block[0] + 1;
119 if (cmd.info.datalen > 6)
120 return -EINVAL;
121 if (!read)
122 memcpy(cmd.info.data, data->block, cmd.info.datalen);
123 cmd.info.sublen = 1;
124 cmd.info.subaddr[0] = command;
125 cmd.info.subaddr[1] = 0;
126 cmd.info.subaddr[2] = 0;
127 break;
128 case I2C_SMBUS_I2C_BLOCK_DATA:
129 cmd.info.type = SMU_I2C_TRANSFER_STDSUB;
130 cmd.info.datalen = data->block[0];
131 if (cmd.info.datalen > 7)
132 return -EINVAL;
133 if (!read)
134 memcpy(cmd.info.data, &data->block[1],
135 cmd.info.datalen);
136 cmd.info.sublen = 1;
137 cmd.info.subaddr[0] = command;
138 cmd.info.subaddr[1] = 0;
139 cmd.info.subaddr[2] = 0;
140 break;
142 default:
143 return -EINVAL;
146 /* Turn a standardsub read into a combined mode access */
147 if (read_write == I2C_SMBUS_READ &&
148 cmd.info.type == SMU_I2C_TRANSFER_STDSUB)
149 cmd.info.type = SMU_I2C_TRANSFER_COMBINED;
151 /* Finish filling command and submit it */
152 cmd.done = smu_i2c_done;
153 cmd.misc = iface;
154 rc = smu_queue_i2c(&cmd);
155 if (rc < 0)
156 return rc;
157 wait_for_completion(&iface->complete);
158 rc = cmd.status;
160 if (!read || rc < 0)
161 return rc;
163 switch (size) {
164 case I2C_SMBUS_BYTE:
165 case I2C_SMBUS_BYTE_DATA:
166 data->byte = cmd.info.data[0];
167 break;
168 case I2C_SMBUS_WORD_DATA:
169 data->word = ((u16)cmd.info.data[1]) << 8;
170 data->word |= cmd.info.data[0];
171 break;
172 /* Note that these are broken vs. the expected smbus API where
173 * on reads, the lenght is actually returned from the function,
174 * but I think the current API makes no sense and I don't want
175 * any driver that I haven't verified for correctness to go
176 * anywhere near a pmac i2c bus anyway ...
178 case I2C_SMBUS_BLOCK_DATA:
179 case I2C_SMBUS_I2C_BLOCK_DATA:
180 memcpy(&data->block[0], cmd.info.data, cmd.info.datalen);
181 break;
184 return rc;
187 static u32
188 smu_smbus_func(struct i2c_adapter * adapter)
190 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
191 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
192 I2C_FUNC_SMBUS_BLOCK_DATA;
195 /* For now, we only handle combined mode (smbus) */
196 static struct i2c_algorithm smu_algorithm = {
197 .smbus_xfer = smu_smbus_xfer,
198 .functionality = smu_smbus_func,
201 static int create_iface(struct device_node *np, struct device *dev)
203 struct smu_iface* iface;
204 u32 *reg, busid;
205 int rc;
207 reg = (u32 *)get_property(np, "reg", NULL);
208 if (reg == NULL) {
209 printk(KERN_ERR "i2c-pmac-smu: can't find bus number !\n");
210 return -ENXIO;
212 busid = *reg;
214 iface = kmalloc(sizeof(struct smu_iface), GFP_KERNEL);
215 if (iface == NULL) {
216 printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n");
217 return -ENOMEM;
219 memset(iface, 0, sizeof(struct smu_iface));
220 init_completion(&iface->complete);
221 iface->busid = busid;
223 dev_set_drvdata(dev, iface);
225 sprintf(iface->adapter.name, "smu-i2c-%02x", busid);
226 iface->adapter.algo = &smu_algorithm;
227 iface->adapter.algo_data = NULL;
228 iface->adapter.client_register = NULL;
229 iface->adapter.client_unregister = NULL;
230 i2c_set_adapdata(&iface->adapter, iface);
231 iface->adapter.dev.parent = dev;
233 rc = i2c_add_adapter(&iface->adapter);
234 if (rc) {
235 printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration "
236 "failed\n", iface->adapter.name);
237 i2c_set_adapdata(&iface->adapter, NULL);
240 if (probe) {
241 unsigned char addr;
242 printk("Probe: ");
243 for (addr = 0x00; addr <= 0x7f; addr++) {
244 if (i2c_smbus_xfer(&iface->adapter,addr,
245 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
246 printk("%02x ", addr);
248 printk("\n");
251 printk(KERN_INFO "SMU i2c bus %x registered\n", busid);
253 return 0;
256 static int dispose_iface(struct device *dev)
258 struct smu_iface *iface = dev_get_drvdata(dev);
259 int rc;
261 rc = i2c_del_adapter(&iface->adapter);
262 i2c_set_adapdata(&iface->adapter, NULL);
263 /* We aren't that prepared to deal with this... */
264 if (rc)
265 printk("i2c-pmac-smu.c: Failed to remove bus %s !\n",
266 iface->adapter.name);
267 dev_set_drvdata(dev, NULL);
268 kfree(iface);
270 return 0;
274 static int create_iface_of_platform(struct of_device* dev,
275 const struct of_device_id *match)
277 return create_iface(dev->node, &dev->dev);
281 static int dispose_iface_of_platform(struct of_device* dev)
283 return dispose_iface(&dev->dev);
287 static struct of_device_id i2c_smu_match[] =
290 .compatible = "smu-i2c",
294 static struct of_platform_driver i2c_smu_of_platform_driver =
296 .name = "i2c-smu",
297 .match_table = i2c_smu_match,
298 .probe = create_iface_of_platform,
299 .remove = dispose_iface_of_platform
303 static int __init i2c_pmac_smu_init(void)
305 of_register_driver(&i2c_smu_of_platform_driver);
306 return 0;
310 static void __exit i2c_pmac_smu_cleanup(void)
312 of_unregister_driver(&i2c_smu_of_platform_driver);
315 module_init(i2c_pmac_smu_init);
316 module_exit(i2c_pmac_smu_cleanup);