]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/i2c/busses/i2c-pmac-smu.c
[PATCH] 1/5 powerpc: Rework PowerMac i2c part 1
[linux-2.6-omap-h63xx.git] / drivers / i2c / busses / i2c-pmac-smu.c
1 /*
2     i2c Support for Apple SMU Controller
3
4     Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
5                        <benh@kernel.crashing.org>
6
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.
11
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.
16
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.
20
21 */
22
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>
34
35 static int probe;
36
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);
41
42
43 /* Physical interface */
44 struct smu_iface
45 {
46         struct i2c_adapter      adapter;
47         struct completion       complete;
48         u32                     busid;
49 };
50
51 static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc)
52 {
53         struct smu_iface        *iface = misc;
54         complete(&iface->complete);
55 }
56
57 /*
58  * SMBUS-type transfer entrypoint
59  */
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)
67 {
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);
72
73         cmd.info.bus = iface->busid;
74         cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00);
75
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->word & 0xff;
107                         cmd.info.data[1] = (data->word >> 8) & 0xff;
108                 }
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 ...
115          */
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 > (SMU_I2C_WRITE_MAX + 1))
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;
141
142         default:
143                 return -EINVAL;
144         }
145
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;
150
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;
159
160         if (!read || rc < 0)
161                 return rc;
162
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 ...
177          */
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;
182         }
183
184         return rc;
185 }
186
187 static u32
188 smu_smbus_func(struct i2c_adapter * adapter)
189 {
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;
193 }
194
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,
199 };
200
201 static int create_iface(struct device_node *np, struct device *dev)
202 {
203         struct smu_iface* iface;
204         u32 *reg, busid;
205         int rc;
206
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;
211         }
212         busid = *reg;
213
214         iface = kzalloc(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;
218         }
219         init_completion(&iface->complete);
220         iface->busid = busid;
221
222         dev_set_drvdata(dev, iface);
223
224         sprintf(iface->adapter.name, "smu-i2c-%02x", busid);
225         iface->adapter.algo = &smu_algorithm;
226         iface->adapter.algo_data = NULL;
227         iface->adapter.client_register = NULL;
228         iface->adapter.client_unregister = NULL;
229         i2c_set_adapdata(&iface->adapter, iface);
230         iface->adapter.dev.parent = dev;
231
232         rc = i2c_add_adapter(&iface->adapter);
233         if (rc) {
234                 printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration "
235                        "failed\n", iface->adapter.name);
236                 i2c_set_adapdata(&iface->adapter, NULL);
237         }
238
239         if (probe) {
240                 unsigned char addr;
241                 printk("Probe: ");
242                 for (addr = 0x00; addr <= 0x7f; addr++) {
243                         if (i2c_smbus_xfer(&iface->adapter,addr,
244                                            0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
245                                 printk("%02x ", addr);
246                 }
247                 printk("\n");
248         }
249
250         printk(KERN_INFO "SMU i2c bus %x registered\n", busid);
251
252         return 0;
253 }
254
255 static int dispose_iface(struct device *dev)
256 {
257         struct smu_iface *iface = dev_get_drvdata(dev);
258         int rc;
259
260         rc = i2c_del_adapter(&iface->adapter);
261         i2c_set_adapdata(&iface->adapter, NULL);
262         /* We aren't that prepared to deal with this... */
263         if (rc)
264                 printk("i2c-pmac-smu.c: Failed to remove bus %s !\n",
265                        iface->adapter.name);
266         dev_set_drvdata(dev, NULL);
267         kfree(iface);
268
269         return 0;
270 }
271
272
273 static int create_iface_of_platform(struct of_device* dev,
274                                     const struct of_device_id *match)
275 {
276         struct device_node *node = dev->node;
277
278         if (device_is_compatible(node, "smu-i2c") ||
279             (node->parent != NULL &&
280              device_is_compatible(node->parent, "smu-i2c-control")))
281                 return create_iface(node, &dev->dev);
282         return -ENODEV;
283 }
284
285
286 static int dispose_iface_of_platform(struct of_device* dev)
287 {
288         return dispose_iface(&dev->dev);
289 }
290
291
292 static struct of_device_id i2c_smu_match[] =
293 {
294         {
295                 .compatible     = "smu-i2c",
296         },
297         {
298                 .compatible     = "i2c-bus",
299         },
300         {},
301 };
302 static struct of_platform_driver i2c_smu_of_platform_driver =
303 {
304         .name           = "i2c-smu",
305         .match_table    = i2c_smu_match,
306         .probe          = create_iface_of_platform,
307         .remove         = dispose_iface_of_platform
308 };
309
310
311 static int __init i2c_pmac_smu_init(void)
312 {
313         of_register_driver(&i2c_smu_of_platform_driver);
314         return 0;
315 }
316
317
318 static void __exit i2c_pmac_smu_cleanup(void)
319 {
320         of_unregister_driver(&i2c_smu_of_platform_driver);
321 }
322
323 module_init(i2c_pmac_smu_init);
324 module_exit(i2c_pmac_smu_cleanup);