Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / i2c / busses / i2c-scmi.c
1 /*
2  * SMBus driver for ACPI SMBus CMI
3  *
4  * Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation version 2.
9  */
10
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/kernel.h>
14 #include <linux/stddef.h>
15 #include <linux/init.h>
16 #include <linux/i2c.h>
17 #include <linux/acpi.h>
18
19 #define ACPI_SMBUS_HC_CLASS             "smbus"
20 #define ACPI_SMBUS_HC_DEVICE_NAME       "cmi"
21
22 ACPI_MODULE_NAME("smbus_cmi");
23
24 struct smbus_methods_t {
25         char *mt_info;
26         char *mt_sbr;
27         char *mt_sbw;
28 };
29
30 struct acpi_smbus_cmi {
31         acpi_handle handle;
32         struct i2c_adapter adapter;
33         u8 cap_info:1;
34         u8 cap_read:1;
35         u8 cap_write:1;
36 };
37
38 static const struct smbus_methods_t smbus_methods = {
39         .mt_info = "_SBI",
40         .mt_sbr  = "_SBR",
41         .mt_sbw  = "_SBW",
42 };
43
44 static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
45         {"SMBUS01", 0},
46         {"", 0}
47 };
48
49 #define ACPI_SMBUS_STATUS_OK                    0x00
50 #define ACPI_SMBUS_STATUS_FAIL                  0x07
51 #define ACPI_SMBUS_STATUS_DNAK                  0x10
52 #define ACPI_SMBUS_STATUS_DERR                  0x11
53 #define ACPI_SMBUS_STATUS_CMD_DENY              0x12
54 #define ACPI_SMBUS_STATUS_UNKNOWN               0x13
55 #define ACPI_SMBUS_STATUS_ACC_DENY              0x17
56 #define ACPI_SMBUS_STATUS_TIMEOUT               0x18
57 #define ACPI_SMBUS_STATUS_NOTSUP                0x19
58 #define ACPI_SMBUS_STATUS_BUSY                  0x1a
59 #define ACPI_SMBUS_STATUS_PEC                   0x1f
60
61 #define ACPI_SMBUS_PRTCL_WRITE                  0x00
62 #define ACPI_SMBUS_PRTCL_READ                   0x01
63 #define ACPI_SMBUS_PRTCL_QUICK                  0x02
64 #define ACPI_SMBUS_PRTCL_BYTE                   0x04
65 #define ACPI_SMBUS_PRTCL_BYTE_DATA              0x06
66 #define ACPI_SMBUS_PRTCL_WORD_DATA              0x08
67 #define ACPI_SMBUS_PRTCL_BLOCK_DATA             0x0a
68
69
70 static int
71 acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
72                    char read_write, u8 command, int size,
73                    union i2c_smbus_data *data)
74 {
75         int result = 0;
76         struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
77         unsigned char protocol;
78         acpi_status status = 0;
79         struct acpi_object_list input;
80         union acpi_object mt_params[5];
81         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
82         union acpi_object *obj;
83         union acpi_object *pkg;
84         char *method;
85         int len = 0;
86
87         dev_dbg(&adap->dev, "access size: %d %s\n", size,
88                 (read_write) ? "READ" : "WRITE");
89         switch (size) {
90         case I2C_SMBUS_QUICK:
91                 protocol = ACPI_SMBUS_PRTCL_QUICK;
92                 command = 0;
93                 if (read_write == I2C_SMBUS_WRITE) {
94                         mt_params[3].type = ACPI_TYPE_INTEGER;
95                         mt_params[3].integer.value = 0;
96                         mt_params[4].type = ACPI_TYPE_INTEGER;
97                         mt_params[4].integer.value = 0;
98                 }
99                 break;
100
101         case I2C_SMBUS_BYTE:
102                 protocol = ACPI_SMBUS_PRTCL_BYTE;
103                 if (read_write == I2C_SMBUS_WRITE) {
104                         mt_params[3].type = ACPI_TYPE_INTEGER;
105                         mt_params[3].integer.value = 0;
106                         mt_params[4].type = ACPI_TYPE_INTEGER;
107                         mt_params[4].integer.value = 0;
108                 } else {
109                         command = 0;
110                 }
111                 break;
112
113         case I2C_SMBUS_BYTE_DATA:
114                 protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
115                 if (read_write == I2C_SMBUS_WRITE) {
116                         mt_params[3].type = ACPI_TYPE_INTEGER;
117                         mt_params[3].integer.value = 1;
118                         mt_params[4].type = ACPI_TYPE_INTEGER;
119                         mt_params[4].integer.value = data->byte;
120                 }
121                 break;
122
123         case I2C_SMBUS_WORD_DATA:
124                 protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
125                 if (read_write == I2C_SMBUS_WRITE) {
126                         mt_params[3].type = ACPI_TYPE_INTEGER;
127                         mt_params[3].integer.value = 2;
128                         mt_params[4].type = ACPI_TYPE_INTEGER;
129                         mt_params[4].integer.value = data->word;
130                 }
131                 break;
132
133         case I2C_SMBUS_BLOCK_DATA:
134                 protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
135                 if (read_write == I2C_SMBUS_WRITE) {
136                         len = data->block[0];
137                         if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
138                                 return -EINVAL;
139                         mt_params[3].type = ACPI_TYPE_INTEGER;
140                         mt_params[3].integer.value = len;
141                         mt_params[4].type = ACPI_TYPE_BUFFER;
142                         mt_params[4].buffer.pointer = data->block + 1;
143                 }
144                 break;
145
146         default:
147                 dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
148                 return -EOPNOTSUPP;
149         }
150
151         if (read_write == I2C_SMBUS_READ) {
152                 protocol |= ACPI_SMBUS_PRTCL_READ;
153                 method = smbus_methods.mt_sbr;
154                 input.count = 3;
155         } else {
156                 protocol |= ACPI_SMBUS_PRTCL_WRITE;
157                 method = smbus_methods.mt_sbw;
158                 input.count = 5;
159         }
160
161         input.pointer = mt_params;
162         mt_params[0].type = ACPI_TYPE_INTEGER;
163         mt_params[0].integer.value = protocol;
164         mt_params[1].type = ACPI_TYPE_INTEGER;
165         mt_params[1].integer.value = addr;
166         mt_params[2].type = ACPI_TYPE_INTEGER;
167         mt_params[2].integer.value = command;
168
169         status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
170                                       &buffer);
171         if (ACPI_FAILURE(status)) {
172                 ACPI_ERROR((AE_INFO, "Evaluating %s: %i", method, status));
173                 return -EIO;
174         }
175
176         pkg = buffer.pointer;
177         if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
178                 obj = pkg->package.elements;
179         else {
180                 ACPI_ERROR((AE_INFO, "Invalid argument type"));
181                 result = -EIO;
182                 goto out;
183         }
184         if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
185                 ACPI_ERROR((AE_INFO, "Invalid argument type"));
186                 result = -EIO;
187                 goto out;
188         }
189
190         result = obj->integer.value;
191         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s return status: %i\n",
192                           method, result));
193
194         switch (result) {
195         case ACPI_SMBUS_STATUS_OK:
196                 result = 0;
197                 break;
198         case ACPI_SMBUS_STATUS_BUSY:
199                 result = -EBUSY;
200                 goto out;
201         case ACPI_SMBUS_STATUS_TIMEOUT:
202                 result = -ETIMEDOUT;
203                 goto out;
204         case ACPI_SMBUS_STATUS_DNAK:
205                 result = -ENXIO;
206                 goto out;
207         default:
208                 result = -EIO;
209                 goto out;
210         }
211
212         if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
213                 goto out;
214
215         obj = pkg->package.elements + 1;
216         if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
217                 ACPI_ERROR((AE_INFO, "Invalid argument type"));
218                 result = -EIO;
219                 goto out;
220         }
221
222         len = obj->integer.value;
223         obj = pkg->package.elements + 2;
224         switch (size) {
225         case I2C_SMBUS_BYTE:
226         case I2C_SMBUS_BYTE_DATA:
227         case I2C_SMBUS_WORD_DATA:
228                 if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
229                         ACPI_ERROR((AE_INFO, "Invalid argument type"));
230                         result = -EIO;
231                         goto out;
232                 }
233                 if (len == 2)
234                         data->word = obj->integer.value;
235                 else
236                         data->byte = obj->integer.value;
237                 break;
238         case I2C_SMBUS_BLOCK_DATA:
239                 if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) {
240                         ACPI_ERROR((AE_INFO, "Invalid argument type"));
241                         result = -EIO;
242                         goto out;
243                 }
244                 if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
245                         return -EPROTO;
246                 data->block[0] = len;
247                 memcpy(data->block + 1, obj->buffer.pointer, len);
248                 break;
249         }
250
251 out:
252         kfree(buffer.pointer);
253         dev_dbg(&adap->dev, "Transaction status: %i\n", result);
254         return result;
255 }
256
257 static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
258 {
259         struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
260         u32 ret;
261
262         ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
263                 I2C_FUNC_SMBUS_QUICK : 0;
264
265         ret |= smbus_cmi->cap_read ?
266                 (I2C_FUNC_SMBUS_READ_BYTE |
267                 I2C_FUNC_SMBUS_READ_BYTE_DATA |
268                 I2C_FUNC_SMBUS_READ_WORD_DATA |
269                 I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
270
271         ret |= smbus_cmi->cap_write ?
272                 (I2C_FUNC_SMBUS_WRITE_BYTE |
273                 I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
274                 I2C_FUNC_SMBUS_WRITE_WORD_DATA |
275                 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
276
277         return ret;
278 }
279
280 static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
281         .smbus_xfer = acpi_smbus_cmi_access,
282         .functionality = acpi_smbus_cmi_func,
283 };
284
285
286 static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
287                                   const char *name)
288 {
289         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
290         union acpi_object *obj;
291         acpi_status status;
292
293         if (!strcmp(name, smbus_methods.mt_info)) {
294                 status = acpi_evaluate_object(smbus_cmi->handle,
295                                         smbus_methods.mt_info,
296                                         NULL, &buffer);
297                 if (ACPI_FAILURE(status)) {
298                         ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
299                                    smbus_methods.mt_info, status));
300                         return -EIO;
301                 }
302
303                 obj = buffer.pointer;
304                 if (obj && obj->type == ACPI_TYPE_PACKAGE)
305                         obj = obj->package.elements;
306                 else {
307                         ACPI_ERROR((AE_INFO, "Invalid argument type"));
308                         kfree(buffer.pointer);
309                         return -EIO;
310                 }
311
312                 if (obj->type != ACPI_TYPE_INTEGER) {
313                         ACPI_ERROR((AE_INFO, "Invalid argument type"));
314                         kfree(buffer.pointer);
315                         return -EIO;
316                 } else
317                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SMBus CMI Version %x"
318                                           "\n", (int)obj->integer.value));
319
320                 kfree(buffer.pointer);
321                 smbus_cmi->cap_info = 1;
322         } else if (!strcmp(name, smbus_methods.mt_sbr))
323                 smbus_cmi->cap_read = 1;
324         else if (!strcmp(name, smbus_methods.mt_sbw))
325                 smbus_cmi->cap_write = 1;
326         else
327                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
328                                  name));
329
330         return 0;
331 }
332
333 static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
334                         void *context, void **return_value)
335 {
336         char node_name[5];
337         struct acpi_buffer buffer = { sizeof(node_name), node_name };
338         struct acpi_smbus_cmi *smbus_cmi = context;
339         acpi_status status;
340
341         status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
342
343         if (ACPI_SUCCESS(status))
344                 acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
345
346         return AE_OK;
347 }
348
349 static int acpi_smbus_cmi_add(struct acpi_device *device)
350 {
351         struct acpi_smbus_cmi *smbus_cmi;
352
353         smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
354         if (!smbus_cmi)
355                 return -ENOMEM;
356
357         smbus_cmi->handle = device->handle;
358         strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
359         strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
360         device->driver_data = smbus_cmi;
361         smbus_cmi->cap_info = 0;
362         smbus_cmi->cap_read = 0;
363         smbus_cmi->cap_write = 0;
364
365         acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
366                             acpi_smbus_cmi_query_methods, smbus_cmi, NULL);
367
368         if (smbus_cmi->cap_info == 0)
369                 goto err;
370
371         snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
372                 "SMBus CMI adapter %s",
373                 acpi_device_name(device));
374         smbus_cmi->adapter.owner = THIS_MODULE;
375         smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
376         smbus_cmi->adapter.algo_data = smbus_cmi;
377         smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
378         smbus_cmi->adapter.dev.parent = &device->dev;
379
380         if (i2c_add_adapter(&smbus_cmi->adapter)) {
381                 dev_err(&device->dev, "Couldn't register adapter!\n");
382                 goto err;
383         }
384
385         return 0;
386
387 err:
388         kfree(smbus_cmi);
389         device->driver_data = NULL;
390         return -EIO;
391 }
392
393 static int acpi_smbus_cmi_remove(struct acpi_device *device, int type)
394 {
395         struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
396
397         i2c_del_adapter(&smbus_cmi->adapter);
398         kfree(smbus_cmi);
399         device->driver_data = NULL;
400
401         return 0;
402 }
403
404 static struct acpi_driver acpi_smbus_cmi_driver = {
405         .name = ACPI_SMBUS_HC_DEVICE_NAME,
406         .class = ACPI_SMBUS_HC_CLASS,
407         .ids = acpi_smbus_cmi_ids,
408         .ops = {
409                 .add = acpi_smbus_cmi_add,
410                 .remove = acpi_smbus_cmi_remove,
411         },
412 };
413
414 static int __init acpi_smbus_cmi_init(void)
415 {
416         return acpi_bus_register_driver(&acpi_smbus_cmi_driver);
417 }
418
419 static void __exit acpi_smbus_cmi_exit(void)
420 {
421         acpi_bus_unregister_driver(&acpi_smbus_cmi_driver);
422 }
423
424 module_init(acpi_smbus_cmi_init);
425 module_exit(acpi_smbus_cmi_exit);
426
427 MODULE_LICENSE("GPL");
428 MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
429 MODULE_DESCRIPTION("ACPI SMBus CMI driver");